存客宝 React

This commit is contained in:
柳清爽
2025-03-29 16:50:39 +08:00
parent caea0b4b99
commit 7e7c199996
388 changed files with 53282 additions and 2076 deletions

View File

@@ -0,0 +1,143 @@
"use client"
import { useState } from "react"
import { useRouter } from "next/navigation"
import { ChevronLeft, Search } from "lucide-react"
import { Button } from "@/components/ui/button"
import { StepIndicator } from "../../components/step-indicator"
import { BasicSettings } from "../../components/basic-settings"
import { DeviceSelectionDialog } from "../../components/device-selection-dialog"
import { Input } from "@/components/ui/input"
export default function EditMomentsSyncPage() {
const router = useRouter()
const [currentStep, setCurrentStep] = useState(1)
const [deviceDialogOpen, setDeviceDialogOpen] = useState(false)
const [formData, setFormData] = useState({
taskName: "同步卡若主号",
startTime: "06:00",
endTime: "23:59",
syncCount: 5,
accountType: "business" as const,
enabled: true,
selectedDevices: [] as string[],
selectedLibraries: [] as string[],
})
const handleUpdateFormData = (data: Partial<typeof formData>) => {
setFormData((prev) => ({ ...prev, ...data }))
}
const handleNext = () => {
setCurrentStep((prev) => Math.min(prev + 1, 3))
}
const handlePrev = () => {
setCurrentStep((prev) => Math.max(prev - 1, 1))
}
const handleComplete = () => {
console.log("Form submitted:", formData)
router.push("/workspace/moments-sync")
}
return (
<div className="min-h-screen bg-[#F8F9FA] pb-20">
<header className="sticky top-0 z-10 bg-white">
<div className="flex items-center h-14 px-4">
<Button variant="ghost" size="icon" onClick={() => router.back()} className="hover:bg-gray-50">
<ChevronLeft className="h-6 w-6" />
</Button>
<h1 className="ml-2 text-lg font-medium"></h1>
</div>
</header>
<div className="mt-8">
<StepIndicator currentStep={currentStep} />
<div className="mt-8">
{currentStep === 1 && (
<BasicSettings formData={formData} onChange={handleUpdateFormData} onNext={handleNext} />
)}
{currentStep === 2 && (
<div className="space-y-6 px-6">
<div className="relative">
<Search className="absolute left-3 top-4 h-5 w-5 text-gray-400" />
<Input
placeholder="选择设备"
className="h-12 pl-11 rounded-xl border-gray-200 text-base"
onClick={() => setDeviceDialogOpen(true)}
readOnly
/>
</div>
{formData.selectedDevices.length > 0 && (
<div className="text-base text-gray-500">{formData.selectedDevices.length} </div>
)}
<div className="flex space-x-4 pt-4">
<Button variant="outline" onClick={handlePrev} className="flex-1 h-12 rounded-xl text-base">
</Button>
<Button
onClick={handleNext}
className="flex-1 h-12 bg-blue-600 hover:bg-blue-700 rounded-xl text-base shadow-sm"
>
</Button>
</div>
<DeviceSelectionDialog
open={deviceDialogOpen}
onOpenChange={setDeviceDialogOpen}
selectedDevices={formData.selectedDevices}
onSelect={(devices) => {
handleUpdateFormData({ selectedDevices: devices })
setDeviceDialogOpen(false)
}}
/>
</div>
)}
{currentStep === 3 && (
<div className="space-y-6 px-6">
<div className="relative">
<Search className="absolute left-3 top-4 h-5 w-5 text-gray-400" />
<Input placeholder="选择内容库" className="h-12 pl-11 rounded-xl border-gray-200 text-base" />
</div>
<div className="flex space-x-4 pt-4">
<Button variant="outline" onClick={handlePrev} className="flex-1 h-12 rounded-xl text-base">
</Button>
<Button
onClick={handleComplete}
className="flex-1 h-12 bg-blue-600 hover:bg-blue-700 rounded-xl text-base shadow-sm"
>
</Button>
</div>
</div>
)}
</div>
</div>
<nav className="fixed bottom-0 left-0 right-0 h-16 bg-white border-t flex items-center justify-around px-6">
<button className="flex flex-col items-center text-blue-600">
<span className="text-sm mt-1"></span>
</button>
<button className="flex flex-col items-center text-gray-400">
<span className="text-sm mt-1"></span>
</button>
<button className="flex flex-col items-center text-gray-400">
<span className="text-sm mt-1"></span>
</button>
<button className="flex flex-col items-center text-gray-400">
<span className="text-sm mt-1"></span>
</button>
</nav>
</div>
)
}

View File

@@ -0,0 +1,39 @@
interface StepIndicatorProps {
currentStep: number
}
export function StepIndicator({ currentStep }: StepIndicatorProps) {
const steps = [
{ number: 1, title: "步骤 1", subtitle: "基础设置" },
{ number: 2, title: "步骤 2", subtitle: "设备选择" },
{ number: 3, title: "步骤 3", subtitle: "选择内容库" },
]
return (
<div className="flex justify-between relative">
{steps.map((step, index) => (
<div key={step.number} className="flex flex-col items-center relative z-10">
<div
className={`w-8 h-8 rounded-full flex items-center justify-center text-sm
${currentStep >= step.number ? "bg-blue-600 text-white" : "bg-gray-100 text-gray-400"}`}
>
{step.number}
</div>
<div className={`text-xs mt-2 ${currentStep >= step.number ? "text-blue-600" : "text-gray-400"}`}>
{step.title}
</div>
<div className={`text-xs ${currentStep >= step.number ? "text-gray-600" : "text-gray-400"}`}>
{step.subtitle}
</div>
</div>
))}
<div className="absolute top-4 left-0 right-0 h-[1px] bg-gray-200 -z-10">
<div
className="h-full bg-blue-600 transition-all duration-300"
style={{ width: `${((currentStep - 1) / (steps.length - 1)) * 100}%` }}
/>
</div>
</div>
)
}

View File

@@ -0,0 +1,101 @@
"use client"
import { Input } from "@/components/ui/input"
import { Button } from "@/components/ui/button"
import { Switch } from "@/components/ui/switch"
import { Plus, Minus } from "lucide-react"
interface BasicSettingsProps {
formData: {
taskName: string
startTime: string
endTime: string
syncCount: number
accountType: string
enabled: boolean
}
onChange: (data: Partial<BasicSettingsProps["formData"]>) => void
onNext: () => void
}
export function BasicSettings({ formData, onChange, onNext }: BasicSettingsProps) {
return (
<div className="space-y-6">
<div>
<div className="text-sm mb-2"></div>
<Input
value={formData.taskName}
onChange={(e) => onChange({ taskName: e.target.value })}
placeholder="请输入任务名称"
/>
</div>
<div>
<div className="text-sm mb-2"></div>
<div className="flex items-center space-x-3">
<Input
type="time"
value={formData.startTime}
onChange={(e) => onChange({ startTime: e.target.value })}
className="w-32"
/>
<span className="text-gray-500"></span>
<Input
type="time"
value={formData.endTime}
onChange={(e) => onChange({ endTime: e.target.value })}
className="w-32"
/>
</div>
</div>
<div>
<div className="text-sm mb-2"></div>
<div className="flex items-center space-x-4">
<Button
variant="outline"
size="icon"
onClick={() => onChange({ syncCount: Math.max(1, formData.syncCount - 1) })}
>
<Minus className="h-4 w-4" />
</Button>
<span className="w-8 text-center">{formData.syncCount}</span>
<Button variant="outline" size="icon" onClick={() => onChange({ syncCount: formData.syncCount + 1 })}>
<Plus className="h-4 w-4" />
</Button>
<span className="text-gray-500"></span>
</div>
</div>
<div>
<div className="text-sm mb-2"></div>
<div className="flex space-x-4">
<Button
variant={formData.accountType === "business" ? "default" : "outline"}
onClick={() => onChange({ accountType: "business" })}
className="flex-1"
>
</Button>
<Button
variant={formData.accountType === "personal" ? "default" : "outline"}
onClick={() => onChange({ accountType: "personal" })}
className="flex-1"
>
</Button>
</div>
</div>
<div className="flex items-center justify-between">
<span className="text-sm"></span>
<Switch checked={formData.enabled} onCheckedChange={(checked) => onChange({ enabled: checked })} />
</div>
<Button onClick={onNext} className="w-full mt-8">
</Button>
</div>
)
}

View File

@@ -0,0 +1,40 @@
"use client"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Search } from "lucide-react"
interface ContentLibrarySelectionProps {
selectedLibraries: string[]
onChange: (libraries: string[]) => void
onComplete: () => void
onPrev: () => void
}
export function ContentLibrarySelection({
selectedLibraries,
onChange,
onComplete,
onPrev,
}: ContentLibrarySelectionProps) {
return (
<div className="space-y-4">
<div className="relative">
<Search className="absolute left-3 top-2.5 h-4 w-4 text-gray-400" />
<Input placeholder="选择内容库" className="pl-9" />
</div>
<div className="min-h-[300px] flex items-center justify-center text-gray-400"></div>
<div className="flex space-x-3 mt-8">
<Button variant="outline" onClick={onPrev} className="flex-1">
</Button>
<Button onClick={onComplete} className="flex-1">
</Button>
</div>
</div>
)
}

View File

@@ -0,0 +1,35 @@
"use client"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Search } from "lucide-react"
interface DeviceSelectionProps {
selectedDevices: string[]
onChange: (devices: string[]) => void
onNext: () => void
onPrev: () => void
}
export function DeviceSelection({ selectedDevices, onChange, onNext, onPrev }: DeviceSelectionProps) {
return (
<div className="space-y-4">
<div className="relative">
<Search className="absolute left-3 top-2.5 h-4 w-4 text-gray-400" />
<Input placeholder="选择设备" className="pl-9" />
</div>
<div className="min-h-[300px] flex items-center justify-center text-gray-400"></div>
<div className="flex space-x-3 mt-8">
<Button variant="outline" onClick={onPrev} className="flex-1">
</Button>
<Button onClick={onNext} className="flex-1">
</Button>
</div>
</div>
)
}