From 943b2da25ca54acadcb598ca0b0757752dca580c Mon Sep 17 00:00:00 2001 From: zetaloop Date: Fri, 20 Feb 2026 22:43:20 +0800 Subject: [PATCH] feat: implement drag-and-drop sorting and save handler for shop templates --- .../dashboard/shop/templates/page.tsx | 108 +++++++++++++++--- 1 file changed, 92 insertions(+), 16 deletions(-) diff --git a/app/(dashboard)/dashboard/shop/templates/page.tsx b/app/(dashboard)/dashboard/shop/templates/page.tsx index 7082e93..0564cd2 100644 --- a/app/(dashboard)/dashboard/shop/templates/page.tsx +++ b/app/(dashboard)/dashboard/shop/templates/page.tsx @@ -2,7 +2,7 @@ import { Eye, EyeOff, GripVertical } from "lucide-react" import Link from "next/link" -import { useState } from "react" +import { type DragEvent, useEffect, useState } from "react" import { Button } from "@/components/ui/button" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Switch } from "@/components/ui/switch" @@ -32,13 +32,75 @@ export default function ShopTemplatesPage() { const [sections, setSections] = useState( [...shop.templateConfig.sections].sort((a, b) => a.order - b.order), ) + const [dragIndex, setDragIndex] = useState(null) + const [dropIndex, setDropIndex] = useState(null) + const [showSavedToast, setShowSavedToast] = useState(false) + + useEffect(() => { + if (!showSavedToast) { + return + } + + const timer = window.setTimeout(() => { + setShowSavedToast(false) + }, 2000) + + return () => { + window.clearTimeout(timer) + } + }, [showSavedToast]) const toggleSection = (type: ShopSection["type"]) => { setSections((prev) => prev.map((s) => (s.type === type ? { ...s, enabled: !s.enabled } : s))) } + const handleDragStart = (index: number) => { + setDragIndex(index) + } + + const handleDragOver = (event: DragEvent, index: number) => { + event.preventDefault() + if (dragIndex === null || dragIndex === index) { + setDropIndex(null) + return + } + setDropIndex(index) + } + + const handleDrop = (event: DragEvent, index: number) => { + event.preventDefault() + if (dragIndex === null || dragIndex === index) { + setDropIndex(null) + return + } + + setSections((prev) => { + const next = [...prev] + const [draggedSection] = next.splice(dragIndex, 1) + next.splice(index, 0, draggedSection) + return next.map((section, order) => ({ ...section, order })) + }) + + setDragIndex(null) + setDropIndex(null) + } + + const handleDragEnd = () => { + setDragIndex(null) + setDropIndex(null) + } + + const handleSaveTemplate = () => { + setShowSavedToast(true) + } + return (
+ {showSavedToast ? ( +
+ 模板已保存 +
+ ) : null}

模板编辑

@@ -48,7 +110,7 @@ export default function ShopTemplatesPage() { - +
@@ -57,20 +119,35 @@ export default function ShopTemplatesPage() { 页面组件 - {sections.map((section) => ( -
- -
-
- {sectionLabels[section.type]} - {section.enabled ? ( - - ) : ( - - )} + {sections.map((section, index) => ( +
+
+ toggleSection(section.type)} @@ -85,7 +162,6 @@ export default function ShopTemplatesPage() { 提示 -

拖拽左侧手柄可调整组件顺序

关闭开关可隐藏对应组件,不会删除已有内容

保存后立即生效,访客将看到最新的店铺主页