数据优化
This commit is contained in:
parent
fa30986946
commit
af1023c3d7
|
|
@ -0,0 +1,58 @@
|
|||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { getPayload } from 'payload'
|
||||
import config from '@payload-config'
|
||||
import { getCache, setCache } from '@/lib/redis'
|
||||
|
||||
/**
|
||||
* GET /api/public/hero-slider
|
||||
* 获取首页幻灯片数据(带缓存)
|
||||
*/
|
||||
export async function GET(req: NextRequest) {
|
||||
try {
|
||||
// 生成缓存 key
|
||||
const cacheKey = 'hero-slider:data'
|
||||
|
||||
// 尝试从缓存获取
|
||||
const cached = await getCache(cacheKey)
|
||||
if (cached) {
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: cached,
|
||||
cached: true,
|
||||
})
|
||||
}
|
||||
|
||||
// 从数据库获取
|
||||
const payload = await getPayload({ config })
|
||||
const result = await payload.findGlobal({
|
||||
slug: 'hero-slider' as any,
|
||||
depth: 2, // 填充图片关联数据
|
||||
})
|
||||
|
||||
// 获取所有幻灯片
|
||||
const slides = (result as any).slides || []
|
||||
|
||||
const responseData = {
|
||||
slides,
|
||||
totalSlides: slides.length,
|
||||
}
|
||||
|
||||
// 缓存结果(1 小时)
|
||||
await setCache(cacheKey, responseData, 3600)
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: responseData,
|
||||
cached: false,
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Hero slider API error:', error)
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to fetch hero slider',
|
||||
},
|
||||
{ status: 500 },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { getPayload } from 'payload'
|
||||
import config from '@payload-config'
|
||||
import { getCache, setCache } from '@/lib/redis'
|
||||
|
||||
/**
|
||||
* GET /api/public/homepage
|
||||
* 获取首页所有数据:幻灯片 + 商品推荐列表(带缓存)
|
||||
*
|
||||
* 这个 API 组合了多个数据源,提供完整的首页内容
|
||||
*/
|
||||
export async function GET(req: NextRequest) {
|
||||
try {
|
||||
// 生成缓存 key
|
||||
const cacheKey = 'homepage:data'
|
||||
|
||||
// 尝试从缓存获取
|
||||
const cached = await getCache(cacheKey)
|
||||
if (cached) {
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: cached,
|
||||
cached: true,
|
||||
})
|
||||
}
|
||||
|
||||
// 从数据库获取数据
|
||||
const payload = await getPayload({ config })
|
||||
|
||||
// 并行获取所有数据
|
||||
const [heroSliderResult, productRecommendationsResult] = await Promise.all([
|
||||
// 获取幻灯片数据
|
||||
payload
|
||||
.findGlobal({
|
||||
slug: 'hero-slider' as any,
|
||||
depth: 2,
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Failed to fetch hero slider:', error)
|
||||
return null
|
||||
}),
|
||||
|
||||
// 获取商品推荐数据
|
||||
payload
|
||||
.findGlobal({
|
||||
slug: 'product-recommendations' as any,
|
||||
depth: 3,
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Failed to fetch product recommendations:', error)
|
||||
return null
|
||||
}),
|
||||
])
|
||||
|
||||
// 处理幻灯片数据
|
||||
let heroSlider = {
|
||||
slides: [],
|
||||
totalSlides: 0,
|
||||
}
|
||||
|
||||
if (heroSliderResult) {
|
||||
const slides = (heroSliderResult as any).slides || []
|
||||
|
||||
heroSlider = {
|
||||
slides,
|
||||
totalSlides: slides.length,
|
||||
}
|
||||
}
|
||||
|
||||
// 处理商品推荐数据
|
||||
let productRecommendations = {
|
||||
enabled: false,
|
||||
lists: [],
|
||||
totalLists: 0,
|
||||
}
|
||||
|
||||
if (productRecommendationsResult && (productRecommendationsResult as any).enabled) {
|
||||
// 获取所有列表
|
||||
const lists = (productRecommendationsResult as any).lists || []
|
||||
|
||||
// 处理每个列表
|
||||
const processedLists = lists.map((list: any) => {
|
||||
const products = Array.isArray(list.products)
|
||||
? list.products.filter((product: any) => product && product.status === 'published')
|
||||
: []
|
||||
|
||||
return {
|
||||
id: list.id,
|
||||
title: list.title,
|
||||
subtitle: list.subtitle,
|
||||
products,
|
||||
totalProducts: products.length,
|
||||
}
|
||||
})
|
||||
|
||||
productRecommendations = {
|
||||
enabled: (productRecommendationsResult as any).enabled,
|
||||
lists: processedLists,
|
||||
totalLists: processedLists.length,
|
||||
}
|
||||
}
|
||||
|
||||
// 组合响应数据
|
||||
const responseData = {
|
||||
heroSlider,
|
||||
productRecommendations,
|
||||
meta: {
|
||||
timestamp: new Date().toISOString(),
|
||||
version: '1.0',
|
||||
},
|
||||
}
|
||||
|
||||
// 缓存结果(1 小时)
|
||||
await setCache(cacheKey, responseData, 3600)
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: responseData,
|
||||
cached: false,
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Homepage API error:', error)
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to fetch homepage data',
|
||||
},
|
||||
{ status: 500 },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { getPayload } from 'payload'
|
||||
import config from '@payload-config'
|
||||
import { getCache, setCache } from '@/lib/redis'
|
||||
|
||||
/**
|
||||
* GET /api/public/product-recommendations
|
||||
* 获取商品推荐列表数据(带缓存)
|
||||
*/
|
||||
export async function GET(req: NextRequest) {
|
||||
try {
|
||||
// 生成缓存 key
|
||||
const cacheKey = 'product-recommendations:data'
|
||||
|
||||
// 尝试从缓存获取
|
||||
const cached = await getCache(cacheKey)
|
||||
if (cached) {
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: cached,
|
||||
cached: true,
|
||||
})
|
||||
}
|
||||
|
||||
// 从数据库获取
|
||||
const payload = await getPayload({ config })
|
||||
const result = await payload.findGlobal({
|
||||
slug: 'product-recommendations' as any,
|
||||
depth: 3, // 填充商品和图片关联数据
|
||||
})
|
||||
|
||||
// 如果功能未启用,返回空数据
|
||||
if (!(result as any).enabled) {
|
||||
const emptyData = {
|
||||
enabled: false,
|
||||
lists: [],
|
||||
}
|
||||
|
||||
// 缓存空数据(较短时间)
|
||||
await setCache(cacheKey, emptyData, 600) // 10 分钟
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: emptyData,
|
||||
cached: false,
|
||||
})
|
||||
}
|
||||
|
||||
// 获取所有列表
|
||||
const lists = (result as any).lists || []
|
||||
|
||||
// 处理每个列表
|
||||
const processedLists = lists.map((list: any) => {
|
||||
const products = Array.isArray(list.products)
|
||||
? list.products.filter((product: any) => product && product.status === 'published')
|
||||
: []
|
||||
|
||||
return {
|
||||
id: list.id,
|
||||
title: list.title,
|
||||
subtitle: list.subtitle,
|
||||
products,
|
||||
totalProducts: products.length,
|
||||
}
|
||||
})
|
||||
|
||||
const responseData = {
|
||||
enabled: (result as any).enabled,
|
||||
lists: processedLists,
|
||||
totalLists: processedLists.length,
|
||||
}
|
||||
|
||||
// 缓存结果(1 小时)
|
||||
await setCache(cacheKey, responseData, 3600)
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: responseData,
|
||||
cached: false,
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Product recommendations API error:', error)
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to fetch product recommendations',
|
||||
},
|
||||
{ status: 500 },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
import type { GlobalConfig } from 'payload'
|
||||
import { deleteCachePattern } from '@/lib/redis'
|
||||
|
||||
export const HeroSlider: GlobalConfig = {
|
||||
slug: 'hero-slider',
|
||||
label: {
|
||||
en: 'Hero Slider',
|
||||
zh: '首页幻灯片',
|
||||
},
|
||||
access: {
|
||||
read: () => true, // 公开可读
|
||||
update: ({ req: { user } }) => {
|
||||
// 只有 admin 和 editor 可以更新
|
||||
if (!user) return false
|
||||
return user.roles?.includes('admin') || user.roles?.includes('editor') || false
|
||||
},
|
||||
},
|
||||
admin: {
|
||||
group: {
|
||||
en: 'Content',
|
||||
zh: '内容管理',
|
||||
},
|
||||
description: {
|
||||
en: 'Manage homepage hero slider/banner',
|
||||
zh: '管理首页轮播图/横幅',
|
||||
},
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'slides',
|
||||
type: 'array',
|
||||
label: {
|
||||
en: 'Slides',
|
||||
zh: '幻灯片',
|
||||
},
|
||||
labels: {
|
||||
singular: {
|
||||
en: 'Slide',
|
||||
zh: '幻灯片',
|
||||
},
|
||||
plural: {
|
||||
en: 'Slides',
|
||||
zh: '幻灯片列表',
|
||||
},
|
||||
},
|
||||
minRows: 1,
|
||||
maxRows: 10,
|
||||
admin: {
|
||||
description: {
|
||||
en: 'Add slides to the hero slider (drag to reorder)',
|
||||
zh: '添加幻灯片(拖动排序)',
|
||||
},
|
||||
initCollapsed: true,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
label: {
|
||||
en: 'Title',
|
||||
zh: '标题',
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'subtitle',
|
||||
type: 'textarea',
|
||||
label: {
|
||||
en: 'Subtitle',
|
||||
zh: '副标题',
|
||||
},
|
||||
maxLength: 200,
|
||||
admin: {
|
||||
rows: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'image',
|
||||
type: 'upload',
|
||||
label: {
|
||||
en: 'Image',
|
||||
zh: '图片',
|
||||
},
|
||||
relationTo: 'media',
|
||||
required: true,
|
||||
admin: {
|
||||
description: {
|
||||
en: 'Recommended: 1920x800px',
|
||||
zh: '推荐尺寸:1920x800px',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'imageMobile',
|
||||
type: 'upload',
|
||||
label: {
|
||||
en: 'Mobile Image',
|
||||
zh: '移动端图片',
|
||||
},
|
||||
relationTo: 'media',
|
||||
admin: {
|
||||
description: {
|
||||
en: 'Optional. Recommended: 750x1000px',
|
||||
zh: '可选。推荐尺寸:750x1000px',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'link',
|
||||
type: 'text',
|
||||
label: {
|
||||
en: 'Link',
|
||||
zh: '链接',
|
||||
},
|
||||
admin: {
|
||||
description: {
|
||||
en: 'Where to go when clicked (e.g., /products)',
|
||||
zh: '点击后跳转的链接(如:/products)',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
hooks: {
|
||||
afterChange: [
|
||||
async ({ doc }) => {
|
||||
try {
|
||||
// 清除 hero-slider 的所有缓存
|
||||
const deletedCount = await deleteCachePattern('hero-slider:*')
|
||||
console.log(`[Cache] Cleared ${deletedCount} cache keys for hero-slider after change`)
|
||||
} catch (error) {
|
||||
console.error('[Cache] Failed to clear hero-slider cache:', error)
|
||||
}
|
||||
return doc
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
import type { GlobalConfig } from 'payload'
|
||||
import { deleteCachePattern } from '@/lib/redis'
|
||||
|
||||
export const ProductRecommendations: GlobalConfig = {
|
||||
slug: 'product-recommendations',
|
||||
label: {
|
||||
en: 'Product Recommendations',
|
||||
zh: '商品推荐',
|
||||
},
|
||||
access: {
|
||||
read: () => true, // 公开可读
|
||||
update: ({ req: { user } }) => {
|
||||
// 只有 admin 和 editor 可以更新
|
||||
if (!user) return false
|
||||
return user.roles?.includes('admin') || user.roles?.includes('editor') || false
|
||||
},
|
||||
},
|
||||
admin: {
|
||||
group: {
|
||||
en: 'Content',
|
||||
zh: '内容管理',
|
||||
},
|
||||
description: {
|
||||
en: 'Manage product recommendation lists for homepage and other pages',
|
||||
zh: '管理首页及其他页面的商品推荐列表',
|
||||
},
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'enabled',
|
||||
type: 'checkbox',
|
||||
label: {
|
||||
en: 'Enable Recommendations',
|
||||
zh: '启用推荐',
|
||||
},
|
||||
defaultValue: true,
|
||||
admin: {
|
||||
description: {
|
||||
en: 'Toggle to show/hide product recommendations',
|
||||
zh: '切换显示/隐藏商品推荐',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'lists',
|
||||
type: 'array',
|
||||
label: {
|
||||
en: 'Recommendation Lists',
|
||||
zh: '推荐列表',
|
||||
},
|
||||
labels: {
|
||||
singular: {
|
||||
en: 'List',
|
||||
zh: '列表',
|
||||
},
|
||||
plural: {
|
||||
en: 'Lists',
|
||||
zh: '列表集合',
|
||||
},
|
||||
},
|
||||
minRows: 0,
|
||||
maxRows: 10,
|
||||
admin: {
|
||||
description: {
|
||||
en: 'Create multiple product recommendation lists (e.g., Hot Items, New Arrivals, Limited Offers)',
|
||||
zh: '创建多个商品推荐列表(如:热门商品、新品上架、限时优惠)',
|
||||
},
|
||||
initCollapsed: true,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
label: {
|
||||
en: 'List Title',
|
||||
zh: '列表标题',
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'subtitle',
|
||||
type: 'textarea',
|
||||
label: {
|
||||
en: 'Subtitle',
|
||||
zh: '副标题',
|
||||
},
|
||||
maxLength: 200,
|
||||
admin: {
|
||||
rows: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'products',
|
||||
type: 'relationship',
|
||||
label: {
|
||||
en: 'Products',
|
||||
zh: '商品列表',
|
||||
},
|
||||
relationTo: 'products',
|
||||
hasMany: true,
|
||||
admin: {
|
||||
description: {
|
||||
en: 'Select and drag to reorder products',
|
||||
zh: '相关商品,支持搜索联想',
|
||||
},
|
||||
components: {
|
||||
Field: '/components/fields/RelatedProductsField#RelatedProductsField',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
hooks: {
|
||||
afterChange: [
|
||||
async ({ doc }) => {
|
||||
try {
|
||||
// 清除商品推荐和首页的所有缓存
|
||||
const deletedCount = await deleteCachePattern('product-recommendations:*')
|
||||
const deletedHomepage = await deleteCachePattern('homepage:*')
|
||||
console.log(
|
||||
`[Cache] Cleared ${deletedCount} product-recommendations cache keys and ${deletedHomepage} homepage cache keys`,
|
||||
)
|
||||
} catch (error) {
|
||||
console.error('[Cache] Failed to clear product-recommendations cache:', error)
|
||||
}
|
||||
return doc
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,370 @@
|
|||
import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres'
|
||||
|
||||
export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
|
||||
await db.execute(sql`
|
||||
CREATE TYPE "public"."enum_users_roles" AS ENUM('admin', 'editor', 'user');
|
||||
CREATE TYPE "public"."enum_announcements_type" AS ENUM('info', 'warning', 'important', 'urgent');
|
||||
CREATE TYPE "public"."enum_announcements_status" AS ENUM('draft', 'published', 'archived');
|
||||
CREATE TYPE "public"."enum_articles_status" AS ENUM('draft', 'published');
|
||||
CREATE TYPE "public"."enum_articles_category" AS ENUM('news', 'tutorial', 'tech', 'review', 'industry', 'other');
|
||||
CREATE TYPE "public"."enum__articles_v_version_status" AS ENUM('draft', 'published');
|
||||
CREATE TYPE "public"."enum__articles_v_version_category" AS ENUM('news', 'tutorial', 'tech', 'review', 'industry', 'other');
|
||||
CREATE TYPE "public"."enum_logs_action" AS ENUM('create', 'update', 'delete', 'sync', 'login', 'logout');
|
||||
CREATE TYPE "public"."enum_payload_jobs_log_task_slug" AS ENUM('inline', 'schedulePublish');
|
||||
CREATE TYPE "public"."enum_payload_jobs_log_state" AS ENUM('failed', 'succeeded');
|
||||
CREATE TYPE "public"."enum_payload_jobs_task_slug" AS ENUM('inline', 'schedulePublish');
|
||||
CREATE TABLE "users_roles" (
|
||||
"order" integer NOT NULL,
|
||||
"parent_id" integer NOT NULL,
|
||||
"value" "enum_users_roles",
|
||||
"id" serial PRIMARY KEY NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "announcements" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"title" varchar NOT NULL,
|
||||
"type" "enum_announcements_type" DEFAULT 'info' NOT NULL,
|
||||
"status" "enum_announcements_status" DEFAULT 'draft' NOT NULL,
|
||||
"priority" numeric DEFAULT 0,
|
||||
"summary" varchar,
|
||||
"content" jsonb NOT NULL,
|
||||
"published_at" timestamp(3) with time zone,
|
||||
"expires_at" timestamp(3) with time zone,
|
||||
"show_on_homepage" boolean DEFAULT false,
|
||||
"author_id" integer,
|
||||
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "articles" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"title" varchar,
|
||||
"status" "enum_articles_status" DEFAULT 'draft',
|
||||
"slug" varchar,
|
||||
"featured_image_id" integer,
|
||||
"excerpt" varchar,
|
||||
"content" jsonb,
|
||||
"category" "enum_articles_category",
|
||||
"featured" boolean DEFAULT false,
|
||||
"author_id" integer,
|
||||
"published_at" timestamp(3) with time zone,
|
||||
"meta_title" varchar,
|
||||
"meta_description" varchar,
|
||||
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"_status" "enum_articles_status" DEFAULT 'draft'
|
||||
);
|
||||
|
||||
CREATE TABLE "articles_texts" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"order" integer NOT NULL,
|
||||
"parent_id" integer NOT NULL,
|
||||
"path" varchar NOT NULL,
|
||||
"text" varchar
|
||||
);
|
||||
|
||||
CREATE TABLE "articles_rels" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"order" integer,
|
||||
"parent_id" integer NOT NULL,
|
||||
"path" varchar NOT NULL,
|
||||
"articles_id" integer,
|
||||
"products_id" integer
|
||||
);
|
||||
|
||||
CREATE TABLE "_articles_v" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"parent_id" integer,
|
||||
"version_title" varchar,
|
||||
"version_status" "enum__articles_v_version_status" DEFAULT 'draft',
|
||||
"version_slug" varchar,
|
||||
"version_featured_image_id" integer,
|
||||
"version_excerpt" varchar,
|
||||
"version_content" jsonb,
|
||||
"version_category" "enum__articles_v_version_category",
|
||||
"version_featured" boolean DEFAULT false,
|
||||
"version_author_id" integer,
|
||||
"version_published_at" timestamp(3) with time zone,
|
||||
"version_meta_title" varchar,
|
||||
"version_meta_description" varchar,
|
||||
"version_updated_at" timestamp(3) with time zone,
|
||||
"version_created_at" timestamp(3) with time zone,
|
||||
"version__status" "enum__articles_v_version_status" DEFAULT 'draft',
|
||||
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"latest" boolean,
|
||||
"autosave" boolean
|
||||
);
|
||||
|
||||
CREATE TABLE "_articles_v_texts" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"order" integer NOT NULL,
|
||||
"parent_id" integer NOT NULL,
|
||||
"path" varchar NOT NULL,
|
||||
"text" varchar
|
||||
);
|
||||
|
||||
CREATE TABLE "_articles_v_rels" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"order" integer,
|
||||
"parent_id" integer NOT NULL,
|
||||
"path" varchar NOT NULL,
|
||||
"articles_id" integer,
|
||||
"products_id" integer
|
||||
);
|
||||
|
||||
CREATE TABLE "logs" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"action" "enum_logs_action" NOT NULL,
|
||||
"collection" varchar NOT NULL,
|
||||
"document_id" varchar,
|
||||
"document_title" varchar,
|
||||
"user_id" integer NOT NULL,
|
||||
"changes" jsonb,
|
||||
"ip" varchar,
|
||||
"user_agent" varchar,
|
||||
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "payload_jobs_log" (
|
||||
"_order" integer NOT NULL,
|
||||
"_parent_id" integer NOT NULL,
|
||||
"id" varchar PRIMARY KEY NOT NULL,
|
||||
"executed_at" timestamp(3) with time zone NOT NULL,
|
||||
"completed_at" timestamp(3) with time zone NOT NULL,
|
||||
"task_slug" "enum_payload_jobs_log_task_slug" NOT NULL,
|
||||
"task_i_d" varchar NOT NULL,
|
||||
"input" jsonb,
|
||||
"output" jsonb,
|
||||
"state" "enum_payload_jobs_log_state" NOT NULL,
|
||||
"error" jsonb
|
||||
);
|
||||
|
||||
CREATE TABLE "payload_jobs" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"input" jsonb,
|
||||
"completed_at" timestamp(3) with time zone,
|
||||
"total_tried" numeric DEFAULT 0,
|
||||
"has_error" boolean DEFAULT false,
|
||||
"error" jsonb,
|
||||
"task_slug" "enum_payload_jobs_task_slug",
|
||||
"queue" varchar DEFAULT 'default',
|
||||
"wait_until" timestamp(3) with time zone,
|
||||
"processing" boolean DEFAULT false,
|
||||
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "admin_settings" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"title" varchar DEFAULT '管理员设置',
|
||||
"updated_at" timestamp(3) with time zone,
|
||||
"created_at" timestamp(3) with time zone
|
||||
);
|
||||
|
||||
CREATE TABLE "logs_manager" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"placeholder" varchar,
|
||||
"updated_at" timestamp(3) with time zone,
|
||||
"created_at" timestamp(3) with time zone
|
||||
);
|
||||
|
||||
CREATE TABLE "hero_slider_slides" (
|
||||
"_order" integer NOT NULL,
|
||||
"_parent_id" integer NOT NULL,
|
||||
"id" varchar PRIMARY KEY NOT NULL,
|
||||
"title" varchar NOT NULL,
|
||||
"subtitle" varchar,
|
||||
"image_id" integer NOT NULL,
|
||||
"image_mobile_id" integer,
|
||||
"link" varchar
|
||||
);
|
||||
|
||||
CREATE TABLE "hero_slider" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"updated_at" timestamp(3) with time zone,
|
||||
"created_at" timestamp(3) with time zone
|
||||
);
|
||||
|
||||
CREATE TABLE "product_recommendations_lists" (
|
||||
"_order" integer NOT NULL,
|
||||
"_parent_id" integer NOT NULL,
|
||||
"id" varchar PRIMARY KEY NOT NULL,
|
||||
"title" varchar NOT NULL,
|
||||
"subtitle" varchar
|
||||
);
|
||||
|
||||
CREATE TABLE "product_recommendations" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"enabled" boolean DEFAULT true,
|
||||
"updated_at" timestamp(3) with time zone,
|
||||
"created_at" timestamp(3) with time zone
|
||||
);
|
||||
|
||||
CREATE TABLE "product_recommendations_rels" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"order" integer,
|
||||
"parent_id" integer NOT NULL,
|
||||
"path" varchar NOT NULL,
|
||||
"products_id" integer
|
||||
);
|
||||
|
||||
ALTER TABLE "products" ADD COLUMN "content" jsonb;
|
||||
ALTER TABLE "payload_locked_documents_rels" ADD COLUMN "announcements_id" integer;
|
||||
ALTER TABLE "payload_locked_documents_rels" ADD COLUMN "articles_id" integer;
|
||||
ALTER TABLE "payload_locked_documents_rels" ADD COLUMN "logs_id" integer;
|
||||
ALTER TABLE "users_roles" ADD CONSTRAINT "users_roles_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "announcements" ADD CONSTRAINT "announcements_author_id_users_id_fk" FOREIGN KEY ("author_id") REFERENCES "public"."users"("id") ON DELETE set null ON UPDATE no action;
|
||||
ALTER TABLE "articles" ADD CONSTRAINT "articles_featured_image_id_media_id_fk" FOREIGN KEY ("featured_image_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action;
|
||||
ALTER TABLE "articles" ADD CONSTRAINT "articles_author_id_users_id_fk" FOREIGN KEY ("author_id") REFERENCES "public"."users"("id") ON DELETE set null ON UPDATE no action;
|
||||
ALTER TABLE "articles_texts" ADD CONSTRAINT "articles_texts_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."articles"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "articles_rels" ADD CONSTRAINT "articles_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."articles"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "articles_rels" ADD CONSTRAINT "articles_rels_articles_fk" FOREIGN KEY ("articles_id") REFERENCES "public"."articles"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "articles_rels" ADD CONSTRAINT "articles_rels_products_fk" FOREIGN KEY ("products_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "_articles_v" ADD CONSTRAINT "_articles_v_parent_id_articles_id_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."articles"("id") ON DELETE set null ON UPDATE no action;
|
||||
ALTER TABLE "_articles_v" ADD CONSTRAINT "_articles_v_version_featured_image_id_media_id_fk" FOREIGN KEY ("version_featured_image_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action;
|
||||
ALTER TABLE "_articles_v" ADD CONSTRAINT "_articles_v_version_author_id_users_id_fk" FOREIGN KEY ("version_author_id") REFERENCES "public"."users"("id") ON DELETE set null ON UPDATE no action;
|
||||
ALTER TABLE "_articles_v_texts" ADD CONSTRAINT "_articles_v_texts_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."_articles_v"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "_articles_v_rels" ADD CONSTRAINT "_articles_v_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."_articles_v"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "_articles_v_rels" ADD CONSTRAINT "_articles_v_rels_articles_fk" FOREIGN KEY ("articles_id") REFERENCES "public"."articles"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "_articles_v_rels" ADD CONSTRAINT "_articles_v_rels_products_fk" FOREIGN KEY ("products_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "logs" ADD CONSTRAINT "logs_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE set null ON UPDATE no action;
|
||||
ALTER TABLE "payload_jobs_log" ADD CONSTRAINT "payload_jobs_log_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."payload_jobs"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "hero_slider_slides" ADD CONSTRAINT "hero_slider_slides_image_id_media_id_fk" FOREIGN KEY ("image_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action;
|
||||
ALTER TABLE "hero_slider_slides" ADD CONSTRAINT "hero_slider_slides_image_mobile_id_media_id_fk" FOREIGN KEY ("image_mobile_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action;
|
||||
ALTER TABLE "hero_slider_slides" ADD CONSTRAINT "hero_slider_slides_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."hero_slider"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "product_recommendations_lists" ADD CONSTRAINT "product_recommendations_lists_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."product_recommendations"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "product_recommendations_rels" ADD CONSTRAINT "product_recommendations_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."product_recommendations"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "product_recommendations_rels" ADD CONSTRAINT "product_recommendations_rels_products_fk" FOREIGN KEY ("products_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;
|
||||
CREATE INDEX "users_roles_order_idx" ON "users_roles" USING btree ("order");
|
||||
CREATE INDEX "users_roles_parent_idx" ON "users_roles" USING btree ("parent_id");
|
||||
CREATE INDEX "announcements_author_idx" ON "announcements" USING btree ("author_id");
|
||||
CREATE INDEX "announcements_updated_at_idx" ON "announcements" USING btree ("updated_at");
|
||||
CREATE INDEX "announcements_created_at_idx" ON "announcements" USING btree ("created_at");
|
||||
CREATE UNIQUE INDEX "articles_slug_idx" ON "articles" USING btree ("slug");
|
||||
CREATE INDEX "articles_featured_image_idx" ON "articles" USING btree ("featured_image_id");
|
||||
CREATE INDEX "articles_author_idx" ON "articles" USING btree ("author_id");
|
||||
CREATE INDEX "articles_updated_at_idx" ON "articles" USING btree ("updated_at");
|
||||
CREATE INDEX "articles_created_at_idx" ON "articles" USING btree ("created_at");
|
||||
CREATE INDEX "articles__status_idx" ON "articles" USING btree ("_status");
|
||||
CREATE INDEX "articles_texts_order_parent" ON "articles_texts" USING btree ("order","parent_id");
|
||||
CREATE INDEX "articles_rels_order_idx" ON "articles_rels" USING btree ("order");
|
||||
CREATE INDEX "articles_rels_parent_idx" ON "articles_rels" USING btree ("parent_id");
|
||||
CREATE INDEX "articles_rels_path_idx" ON "articles_rels" USING btree ("path");
|
||||
CREATE INDEX "articles_rels_articles_id_idx" ON "articles_rels" USING btree ("articles_id");
|
||||
CREATE INDEX "articles_rels_products_id_idx" ON "articles_rels" USING btree ("products_id");
|
||||
CREATE INDEX "_articles_v_parent_idx" ON "_articles_v" USING btree ("parent_id");
|
||||
CREATE INDEX "_articles_v_version_version_slug_idx" ON "_articles_v" USING btree ("version_slug");
|
||||
CREATE INDEX "_articles_v_version_version_featured_image_idx" ON "_articles_v" USING btree ("version_featured_image_id");
|
||||
CREATE INDEX "_articles_v_version_version_author_idx" ON "_articles_v" USING btree ("version_author_id");
|
||||
CREATE INDEX "_articles_v_version_version_updated_at_idx" ON "_articles_v" USING btree ("version_updated_at");
|
||||
CREATE INDEX "_articles_v_version_version_created_at_idx" ON "_articles_v" USING btree ("version_created_at");
|
||||
CREATE INDEX "_articles_v_version_version__status_idx" ON "_articles_v" USING btree ("version__status");
|
||||
CREATE INDEX "_articles_v_created_at_idx" ON "_articles_v" USING btree ("created_at");
|
||||
CREATE INDEX "_articles_v_updated_at_idx" ON "_articles_v" USING btree ("updated_at");
|
||||
CREATE INDEX "_articles_v_latest_idx" ON "_articles_v" USING btree ("latest");
|
||||
CREATE INDEX "_articles_v_autosave_idx" ON "_articles_v" USING btree ("autosave");
|
||||
CREATE INDEX "_articles_v_texts_order_parent" ON "_articles_v_texts" USING btree ("order","parent_id");
|
||||
CREATE INDEX "_articles_v_rels_order_idx" ON "_articles_v_rels" USING btree ("order");
|
||||
CREATE INDEX "_articles_v_rels_parent_idx" ON "_articles_v_rels" USING btree ("parent_id");
|
||||
CREATE INDEX "_articles_v_rels_path_idx" ON "_articles_v_rels" USING btree ("path");
|
||||
CREATE INDEX "_articles_v_rels_articles_id_idx" ON "_articles_v_rels" USING btree ("articles_id");
|
||||
CREATE INDEX "_articles_v_rels_products_id_idx" ON "_articles_v_rels" USING btree ("products_id");
|
||||
CREATE INDEX "logs_collection_idx" ON "logs" USING btree ("collection");
|
||||
CREATE INDEX "logs_document_id_idx" ON "logs" USING btree ("document_id");
|
||||
CREATE INDEX "logs_user_idx" ON "logs" USING btree ("user_id");
|
||||
CREATE INDEX "logs_updated_at_idx" ON "logs" USING btree ("updated_at");
|
||||
CREATE INDEX "logs_created_at_idx" ON "logs" USING btree ("created_at");
|
||||
CREATE INDEX "payload_jobs_log_order_idx" ON "payload_jobs_log" USING btree ("_order");
|
||||
CREATE INDEX "payload_jobs_log_parent_id_idx" ON "payload_jobs_log" USING btree ("_parent_id");
|
||||
CREATE INDEX "payload_jobs_completed_at_idx" ON "payload_jobs" USING btree ("completed_at");
|
||||
CREATE INDEX "payload_jobs_total_tried_idx" ON "payload_jobs" USING btree ("total_tried");
|
||||
CREATE INDEX "payload_jobs_has_error_idx" ON "payload_jobs" USING btree ("has_error");
|
||||
CREATE INDEX "payload_jobs_task_slug_idx" ON "payload_jobs" USING btree ("task_slug");
|
||||
CREATE INDEX "payload_jobs_queue_idx" ON "payload_jobs" USING btree ("queue");
|
||||
CREATE INDEX "payload_jobs_wait_until_idx" ON "payload_jobs" USING btree ("wait_until");
|
||||
CREATE INDEX "payload_jobs_processing_idx" ON "payload_jobs" USING btree ("processing");
|
||||
CREATE INDEX "payload_jobs_updated_at_idx" ON "payload_jobs" USING btree ("updated_at");
|
||||
CREATE INDEX "payload_jobs_created_at_idx" ON "payload_jobs" USING btree ("created_at");
|
||||
CREATE INDEX "hero_slider_slides_order_idx" ON "hero_slider_slides" USING btree ("_order");
|
||||
CREATE INDEX "hero_slider_slides_parent_id_idx" ON "hero_slider_slides" USING btree ("_parent_id");
|
||||
CREATE INDEX "hero_slider_slides_image_idx" ON "hero_slider_slides" USING btree ("image_id");
|
||||
CREATE INDEX "hero_slider_slides_image_mobile_idx" ON "hero_slider_slides" USING btree ("image_mobile_id");
|
||||
CREATE INDEX "product_recommendations_lists_order_idx" ON "product_recommendations_lists" USING btree ("_order");
|
||||
CREATE INDEX "product_recommendations_lists_parent_id_idx" ON "product_recommendations_lists" USING btree ("_parent_id");
|
||||
CREATE INDEX "product_recommendations_rels_order_idx" ON "product_recommendations_rels" USING btree ("order");
|
||||
CREATE INDEX "product_recommendations_rels_parent_idx" ON "product_recommendations_rels" USING btree ("parent_id");
|
||||
CREATE INDEX "product_recommendations_rels_path_idx" ON "product_recommendations_rels" USING btree ("path");
|
||||
CREATE INDEX "product_recommendations_rels_products_id_idx" ON "product_recommendations_rels" USING btree ("products_id");
|
||||
ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_announcements_fk" FOREIGN KEY ("announcements_id") REFERENCES "public"."announcements"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_articles_fk" FOREIGN KEY ("articles_id") REFERENCES "public"."articles"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_logs_fk" FOREIGN KEY ("logs_id") REFERENCES "public"."logs"("id") ON DELETE cascade ON UPDATE no action;
|
||||
CREATE INDEX "payload_locked_documents_rels_announcements_id_idx" ON "payload_locked_documents_rels" USING btree ("announcements_id");
|
||||
CREATE INDEX "payload_locked_documents_rels_articles_id_idx" ON "payload_locked_documents_rels" USING btree ("articles_id");
|
||||
CREATE INDEX "payload_locked_documents_rels_logs_id_idx" ON "payload_locked_documents_rels" USING btree ("logs_id");`)
|
||||
}
|
||||
|
||||
export async function down({ db, payload, req }: MigrateDownArgs): Promise<void> {
|
||||
await db.execute(sql`
|
||||
ALTER TABLE "users_roles" DISABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE "announcements" DISABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE "articles" DISABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE "articles_texts" DISABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE "articles_rels" DISABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE "_articles_v" DISABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE "_articles_v_texts" DISABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE "_articles_v_rels" DISABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE "logs" DISABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE "payload_jobs_log" DISABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE "payload_jobs" DISABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE "admin_settings" DISABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE "logs_manager" DISABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE "hero_slider_slides" DISABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE "hero_slider" DISABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE "product_recommendations_lists" DISABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE "product_recommendations" DISABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE "product_recommendations_rels" DISABLE ROW LEVEL SECURITY;
|
||||
DROP TABLE "users_roles" CASCADE;
|
||||
DROP TABLE "announcements" CASCADE;
|
||||
DROP TABLE "articles" CASCADE;
|
||||
DROP TABLE "articles_texts" CASCADE;
|
||||
DROP TABLE "articles_rels" CASCADE;
|
||||
DROP TABLE "_articles_v" CASCADE;
|
||||
DROP TABLE "_articles_v_texts" CASCADE;
|
||||
DROP TABLE "_articles_v_rels" CASCADE;
|
||||
DROP TABLE "logs" CASCADE;
|
||||
DROP TABLE "payload_jobs_log" CASCADE;
|
||||
DROP TABLE "payload_jobs" CASCADE;
|
||||
DROP TABLE "admin_settings" CASCADE;
|
||||
DROP TABLE "logs_manager" CASCADE;
|
||||
DROP TABLE "hero_slider_slides" CASCADE;
|
||||
DROP TABLE "hero_slider" CASCADE;
|
||||
DROP TABLE "product_recommendations_lists" CASCADE;
|
||||
DROP TABLE "product_recommendations" CASCADE;
|
||||
DROP TABLE "product_recommendations_rels" CASCADE;
|
||||
ALTER TABLE "payload_locked_documents_rels" DROP CONSTRAINT "payload_locked_documents_rels_announcements_fk";
|
||||
|
||||
ALTER TABLE "payload_locked_documents_rels" DROP CONSTRAINT "payload_locked_documents_rels_articles_fk";
|
||||
|
||||
ALTER TABLE "payload_locked_documents_rels" DROP CONSTRAINT "payload_locked_documents_rels_logs_fk";
|
||||
|
||||
DROP INDEX "payload_locked_documents_rels_announcements_id_idx";
|
||||
DROP INDEX "payload_locked_documents_rels_articles_id_idx";
|
||||
DROP INDEX "payload_locked_documents_rels_logs_id_idx";
|
||||
ALTER TABLE "products" DROP COLUMN "content";
|
||||
ALTER TABLE "payload_locked_documents_rels" DROP COLUMN "announcements_id";
|
||||
ALTER TABLE "payload_locked_documents_rels" DROP COLUMN "articles_id";
|
||||
ALTER TABLE "payload_locked_documents_rels" DROP COLUMN "logs_id";
|
||||
DROP TYPE "public"."enum_users_roles";
|
||||
DROP TYPE "public"."enum_announcements_type";
|
||||
DROP TYPE "public"."enum_announcements_status";
|
||||
DROP TYPE "public"."enum_articles_status";
|
||||
DROP TYPE "public"."enum_articles_category";
|
||||
DROP TYPE "public"."enum__articles_v_version_status";
|
||||
DROP TYPE "public"."enum__articles_v_version_category";
|
||||
DROP TYPE "public"."enum_logs_action";
|
||||
DROP TYPE "public"."enum_payload_jobs_log_task_slug";
|
||||
DROP TYPE "public"."enum_payload_jobs_log_state";
|
||||
DROP TYPE "public"."enum_payload_jobs_task_slug";`)
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
import { MigrateUpArgs, sql } from '@payloadcms/db-postgres'
|
||||
|
||||
export async function up({ db }: MigrateUpArgs): Promise<void> {
|
||||
await db.execute(
|
||||
sql`ALTER TABLE hero_slider_slides ADD COLUMN IF NOT EXISTS link TEXT;`
|
||||
)
|
||||
|
||||
await db.execute(
|
||||
sql`UPDATE hero_slider_slides SET link = cta_link WHERE cta_link IS NOT NULL AND cta_enabled = true;`
|
||||
)
|
||||
|
||||
await db.execute(
|
||||
sql`ALTER TABLE hero_slider_slides
|
||||
DROP COLUMN IF EXISTS cta_enabled,
|
||||
DROP COLUMN IF EXISTS cta_text,
|
||||
DROP COLUMN IF EXISTS cta_style,
|
||||
DROP COLUMN IF EXISTS cta_link,
|
||||
DROP COLUMN IF EXISTS cta_new_tab,
|
||||
DROP COLUMN IF EXISTS text_position,
|
||||
DROP COLUMN IF EXISTS text_color,
|
||||
DROP COLUMN IF EXISTS overlay,
|
||||
DROP COLUMN IF EXISTS status;`
|
||||
)
|
||||
}
|
||||
|
|
@ -1,4 +1,7 @@
|
|||
import * as migration_20260208_171142 from './20260208_171142'
|
||||
import * as migration_20260208_171142 from './20260208_171142';
|
||||
import * as migration_20260212_193303 from './20260212_193303';
|
||||
import * as migration_hero_slider_simplify from './hero_slider_simplify';
|
||||
import * as migration_product_recommendations_simplify from './product_recommendations_simplify';
|
||||
|
||||
export const migrations = [
|
||||
{
|
||||
|
|
@ -6,4 +9,17 @@ export const migrations = [
|
|||
down: migration_20260208_171142.down,
|
||||
name: '20260208_171142',
|
||||
},
|
||||
]
|
||||
{
|
||||
up: migration_20260212_193303.up,
|
||||
down: migration_20260212_193303.down,
|
||||
name: '20260212_193303'
|
||||
},
|
||||
{
|
||||
up: migration_hero_slider_simplify.up,
|
||||
name: 'hero_slider_simplify'
|
||||
},
|
||||
{
|
||||
up: migration_product_recommendations_simplify.up,
|
||||
name: 'product_recommendations_simplify'
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
import { MigrateUpArgs, sql } from '@payloadcms/db-postgres'
|
||||
|
||||
export async function up({ db }: MigrateUpArgs): Promise<void> {
|
||||
await db.execute(
|
||||
sql`ALTER TABLE product_recommendations_lists
|
||||
DROP COLUMN IF EXISTS slug,
|
||||
DROP COLUMN IF EXISTS type,
|
||||
DROP COLUMN IF EXISTS display_limit,
|
||||
DROP COLUMN IF EXISTS show_view_all,
|
||||
DROP COLUMN IF EXISTS view_all_link,
|
||||
DROP COLUMN IF EXISTS layout,
|
||||
DROP COLUMN IF EXISTS columns,
|
||||
DROP COLUMN IF EXISTS show_price,
|
||||
DROP COLUMN IF EXISTS show_rating,
|
||||
DROP COLUMN IF EXISTS show_quick_view,
|
||||
DROP COLUMN IF EXISTS status;`
|
||||
)
|
||||
}
|
||||
|
|
@ -100,10 +100,14 @@ export interface Config {
|
|||
globals: {
|
||||
'admin-settings': AdminSetting;
|
||||
'logs-manager': LogsManager;
|
||||
'hero-slider': HeroSlider;
|
||||
'product-recommendations': ProductRecommendation;
|
||||
};
|
||||
globalsSelect: {
|
||||
'admin-settings': AdminSettingsSelect<false> | AdminSettingsSelect<true>;
|
||||
'logs-manager': LogsManagerSelect<false> | LogsManagerSelect<true>;
|
||||
'hero-slider': HeroSliderSelect<false> | HeroSliderSelect<true>;
|
||||
'product-recommendations': ProductRecommendationsSelect<false> | ProductRecommendationsSelect<true>;
|
||||
};
|
||||
locale: null;
|
||||
user: User;
|
||||
|
|
@ -834,6 +838,68 @@ export interface LogsManager {
|
|||
updatedAt?: string | null;
|
||||
createdAt?: string | null;
|
||||
}
|
||||
/**
|
||||
* Manage homepage hero slider/banner
|
||||
*
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "hero-slider".
|
||||
*/
|
||||
export interface HeroSlider {
|
||||
id: number;
|
||||
/**
|
||||
* Add slides to the hero slider (drag to reorder)
|
||||
*/
|
||||
slides?:
|
||||
| {
|
||||
title: string;
|
||||
subtitle?: string | null;
|
||||
/**
|
||||
* Recommended: 1920x800px
|
||||
*/
|
||||
image: number | Media;
|
||||
/**
|
||||
* Optional. Recommended: 750x1000px
|
||||
*/
|
||||
imageMobile?: (number | null) | Media;
|
||||
/**
|
||||
* Where to go when clicked (e.g., /products)
|
||||
*/
|
||||
link?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
updatedAt?: string | null;
|
||||
createdAt?: string | null;
|
||||
}
|
||||
/**
|
||||
* Manage product recommendation lists for homepage and other pages
|
||||
*
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "product-recommendations".
|
||||
*/
|
||||
export interface ProductRecommendation {
|
||||
id: number;
|
||||
/**
|
||||
* Toggle to show/hide product recommendations
|
||||
*/
|
||||
enabled?: boolean | null;
|
||||
/**
|
||||
* Create multiple product recommendation lists (e.g., Hot Items, New Arrivals, Limited Offers)
|
||||
*/
|
||||
lists?:
|
||||
| {
|
||||
title: string;
|
||||
subtitle?: string | null;
|
||||
/**
|
||||
* Select and drag to reorder products
|
||||
*/
|
||||
products?: (number | Product)[] | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
updatedAt?: string | null;
|
||||
createdAt?: string | null;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "admin-settings_select".
|
||||
|
|
@ -854,6 +920,43 @@ export interface LogsManagerSelect<T extends boolean = true> {
|
|||
createdAt?: T;
|
||||
globalType?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "hero-slider_select".
|
||||
*/
|
||||
export interface HeroSliderSelect<T extends boolean = true> {
|
||||
slides?:
|
||||
| T
|
||||
| {
|
||||
title?: T;
|
||||
subtitle?: T;
|
||||
image?: T;
|
||||
imageMobile?: T;
|
||||
link?: T;
|
||||
id?: T;
|
||||
};
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
globalType?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "product-recommendations_select".
|
||||
*/
|
||||
export interface ProductRecommendationsSelect<T extends boolean = true> {
|
||||
enabled?: T;
|
||||
lists?:
|
||||
| T
|
||||
| {
|
||||
title?: T;
|
||||
subtitle?: T;
|
||||
products?: T;
|
||||
id?: T;
|
||||
};
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
globalType?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "TaskSchedulePublish".
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ import { Articles } from './collections/Articles'
|
|||
import { Logs } from './collections/Logs'
|
||||
import { AdminSettings } from './globals/AdminSettings'
|
||||
import { LogsManager } from './globals/LogsManager'
|
||||
import { HeroSlider } from './globals/HeroSlider'
|
||||
import { ProductRecommendations } from './globals/ProductRecommendations'
|
||||
import { s3Storage } from '@payloadcms/storage-s3'
|
||||
import { en } from '@payloadcms/translations/languages/en'
|
||||
import { zh } from '@payloadcms/translations/languages/zh'
|
||||
|
|
@ -45,7 +47,7 @@ export default buildConfig({
|
|||
fallbackLanguage: 'zh',
|
||||
},
|
||||
collections: [Users, Media, Products, Announcements, Articles, Logs],
|
||||
globals: [AdminSettings, LogsManager],
|
||||
globals: [AdminSettings, LogsManager, HeroSlider, ProductRecommendations],
|
||||
editor: lexicalEditor(),
|
||||
secret: process.env.PAYLOAD_SECRET || '',
|
||||
typescript: {
|
||||
|
|
|
|||
Loading…
Reference in New Issue