fix: resolve deployment errors and add missing files

Fix CSS issue and create missing documentation files
Add new data platform and mobile optimization features

Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
This commit is contained in:
v0
2025-07-19 02:34:18 +00:00
parent ea95107713
commit 901763fae0
20 changed files with 3216 additions and 1882 deletions

View File

@@ -1,29 +1,5 @@
"use client"
import { useState, useEffect } from "react"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Textarea } from "@/components/ui/textarea"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { Switch } from "@/components/ui/switch"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { Separator } from "@/components/ui/separator"
import { AlertCircle, Plus, X, Save, TestTube } from "lucide-react"
import { Alert, AlertDescription } from "@/components/ui/alert"
interface TagRule {
id?: string
name: string
description: string
conditions: RuleCondition[]
actions: RuleAction[]
priority: number
enabled: boolean
schedule?: RuleSchedule
}
interface RuleCondition {
field: string
operator: string
@@ -31,533 +7,11 @@ interface RuleCondition {
logicalOperator?: "AND" | "OR"
}
interface RuleAction {
type: "add_tag" | "remove_tag" | "update_field"
target: string
value: string
}
interface RuleSchedule {
type: "immediate" | "scheduled" | "recurring"
startTime?: string
interval?: string
}
interface RuleEditorProps {
ruleId?: string
onSave: (rule: TagRule) => void
onCancel: () => void
}
export function RuleEditor({ ruleId, onSave, onCancel }: RuleEditorProps) {
const [rule, setRule] = useState<TagRule>({
name: "",
description: "",
conditions: [{ field: "", operator: "", value: "" }],
actions: [{ type: "add_tag", target: "", value: "" }],
priority: 1,
enabled: true,
})
const [isLoading, setIsLoading] = useState(false)
const [testResults, setTestResults] = useState<any>(null)
const [validationErrors, setValidationErrors] = useState<string[]>([])
const fieldOptions = [
{ value: "user_type", label: "用户类型" },
{ value: "registration_date", label: "注册日期" },
{ value: "last_login", label: "最后登录" },
{ value: "purchase_amount", label: "购买金额" },
{ value: "activity_score", label: "活跃度评分" },
{ value: "device_type", label: "设备类型" },
{ value: "location", label: "地理位置" },
{ value: "age", label: "年龄" },
{ value: "gender", label: "性别" },
]
const operatorOptions = [
{ value: "equals", label: "等于" },
{ value: "not_equals", label: "不等于" },
{ value: "greater_than", label: "大于" },
{ value: "less_than", label: "小于" },
{ value: "contains", label: "包含" },
{ value: "not_contains", label: "不包含" },
{ value: "starts_with", label: "开始于" },
{ value: "ends_with", label: "结束于" },
{ value: "in_range", label: "在范围内" },
]
useEffect(() => {
if (ruleId) {
loadRule(ruleId)
}
}, [ruleId])
const loadRule = async (id: string) => {
setIsLoading(true)
try {
// 模拟API调用
await new Promise((resolve) => setTimeout(resolve, 1000))
// 这里应该从API加载规则数据
setRule({
id,
name: "示例规则",
description: "这是一个示例规则",
conditions: [{ field: "user_type", operator: "equals", value: "premium" }],
actions: [{ type: "add_tag", target: "tag", value: "高价值用户" }],
priority: 1,
enabled: true,
})
} catch (error) {
console.error("加载规则失败:", error)
} finally {
setIsLoading(false)
}
}
const validateRule = (): string[] => {
const errors: string[] = []
if (!rule.name.trim()) {
errors.push("规则名称不能为空")
}
if (rule.conditions.length === 0) {
errors.push("至少需要一个条件")
}
rule.conditions.forEach((condition, index) => {
if (!condition.field || !condition.operator || !condition.value) {
errors.push(`条件 ${index + 1} 不完整`)
}
})
if (rule.actions.length === 0) {
errors.push("至少需要一个动作")
}
rule.actions.forEach((action, index) => {
if (!action.target || !action.value) {
errors.push(`动作 ${index + 1} 不完整`)
}
})
return errors
}
const handleSave = () => {
const errors = validateRule()
setValidationErrors(errors)
if (errors.length === 0) {
onSave(rule)
}
}
const handleTest = async () => {
setIsLoading(true)
try {
// 模拟测试规则
await new Promise((resolve) => setTimeout(resolve, 2000))
setTestResults({
matchedUsers: 156,
estimatedImpact: "将为156个用户添加标签",
executionTime: "预计执行时间: 2分钟",
})
} catch (error) {
console.error("测试规则失败:", error)
} finally {
setIsLoading(false)
}
}
const addCondition = () => {
setRule({
...rule,
conditions: [...rule.conditions, { field: "", operator: "", value: "" }],
})
}
const removeCondition = (index: number) => {
const newConditions = rule.conditions.filter((_, i) => i !== index)
setRule({ ...rule, conditions: newConditions })
}
const updateCondition = (index: number, field: keyof RuleCondition, value: string) => {
const newConditions = [...rule.conditions]
newConditions[index] = { ...newConditions[index], [field]: value }
setRule({ ...rule, conditions: newConditions })
}
const addAction = () => {
setRule({
...rule,
actions: [...rule.actions, { type: "add_tag", target: "", value: "" }],
})
}
const removeAction = (index: number) => {
const newActions = rule.actions.filter((_, i) => i !== index)
setRule({ ...rule, actions: newActions })
}
const updateAction = (index: number, field: keyof RuleAction, value: string) => {
const newActions = [...rule.actions]
newActions[index] = { ...newActions[index], [field]: value }
setRule({ ...rule, actions: newActions })
}
if (isLoading && !rule.name) {
return (
<Card>
<CardContent className="flex items-center justify-center h-64">
<div className="text-center">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600 mx-auto mb-4"></div>
<p>...</p>
</div>
</CardContent>
</Card>
)
}
return (
<Card>
<CardHeader>
<CardTitle>{ruleId ? "编辑规则" : "创建新规则"}</CardTitle>
<CardDescription>{ruleId ? "修改现有标签规则的配置" : "创建新的自动化标签规则"}</CardDescription>
</CardHeader>
<CardContent>
<Tabs defaultValue="basic" className="w-full">
<TabsList className="grid w-full grid-cols-4">
<TabsTrigger value="basic"></TabsTrigger>
<TabsTrigger value="conditions"></TabsTrigger>
<TabsTrigger value="actions"></TabsTrigger>
<TabsTrigger value="schedule"></TabsTrigger>
</TabsList>
<TabsContent value="basic" className="space-y-4">
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="name"></Label>
<Input
id="name"
value={rule.name}
onChange={(e) => setRule({ ...rule, name: e.target.value })}
placeholder="输入规则名称"
/>
</div>
<div className="space-y-2">
<Label htmlFor="priority"></Label>
<Select
value={rule.priority.toString()}
onValueChange={(value) => setRule({ ...rule, priority: Number.parseInt(value) })}
>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="1"> (1)</SelectItem>
<SelectItem value="2"> (2)</SelectItem>
<SelectItem value="3"> (3)</SelectItem>
</SelectContent>
</Select>
</div>
</div>
<div className="space-y-2">
<Label htmlFor="description"></Label>
<Textarea
id="description"
value={rule.description}
onChange={(e) => setRule({ ...rule, description: e.target.value })}
placeholder="描述这个规则的用途和逻辑"
rows={3}
/>
</div>
<div className="flex items-center space-x-2">
<Switch
id="enabled"
checked={rule.enabled}
onCheckedChange={(checked) => setRule({ ...rule, enabled: checked })}
/>
<Label htmlFor="enabled"></Label>
</div>
</TabsContent>
<TabsContent value="conditions" className="space-y-4">
<div className="flex items-center justify-between">
<h3 className="text-lg font-medium"></h3>
<Button onClick={addCondition} size="sm">
<Plus className="h-4 w-4 mr-2" />
</Button>
</div>
<div className="space-y-4">
{rule.conditions.map((condition, index) => (
<div key={index} className="border rounded-lg p-4 space-y-4">
<div className="flex items-center justify-between">
<h4 className="font-medium"> {index + 1}</h4>
{rule.conditions.length > 1 && (
<Button variant="ghost" size="sm" onClick={() => removeCondition(index)}>
<X className="h-4 w-4" />
</Button>
)}
</div>
<div className="grid grid-cols-3 gap-4">
<div className="space-y-2">
<Label></Label>
<Select value={condition.field} onValueChange={(value) => updateCondition(index, "field", value)}>
<SelectTrigger>
<SelectValue placeholder="选择字段" />
</SelectTrigger>
<SelectContent>
{fieldOptions.map((option) => (
<SelectItem key={option.value} value={option.value}>
{option.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label></Label>
<Select
value={condition.operator}
onValueChange={(value) => updateCondition(index, "operator", value)}
>
<SelectTrigger>
<SelectValue placeholder="选择操作符" />
</SelectTrigger>
<SelectContent>
{operatorOptions.map((option) => (
<SelectItem key={option.value} value={option.value}>
{option.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label></Label>
<Input
value={condition.value}
onChange={(e) => updateCondition(index, "value", e.target.value)}
placeholder="输入比较值"
/>
</div>
</div>
{index < rule.conditions.length - 1 && (
<div className="flex items-center space-x-2">
<Label>:</Label>
<Select
value={condition.logicalOperator || "AND"}
onValueChange={(value) => updateCondition(index, "logicalOperator", value)}
>
<SelectTrigger className="w-20">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="AND">AND</SelectItem>
<SelectItem value="OR">OR</SelectItem>
</SelectContent>
</Select>
</div>
)}
</div>
))}
</div>
</TabsContent>
<TabsContent value="actions" className="space-y-4">
<div className="flex items-center justify-between">
<h3 className="text-lg font-medium"></h3>
<Button onClick={addAction} size="sm">
<Plus className="h-4 w-4 mr-2" />
</Button>
</div>
<div className="space-y-4">
{rule.actions.map((action, index) => (
<div key={index} className="border rounded-lg p-4 space-y-4">
<div className="flex items-center justify-between">
<h4 className="font-medium"> {index + 1}</h4>
{rule.actions.length > 1 && (
<Button variant="ghost" size="sm" onClick={() => removeAction(index)}>
<X className="h-4 w-4" />
</Button>
)}
</div>
<div className="grid grid-cols-3 gap-4">
<div className="space-y-2">
<Label></Label>
<Select value={action.type} onValueChange={(value) => updateAction(index, "type", value)}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="add_tag"></SelectItem>
<SelectItem value="remove_tag"></SelectItem>
<SelectItem value="update_field"></SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label></Label>
<Input
value={action.target}
onChange={(e) => updateAction(index, "target", e.target.value)}
placeholder={
action.type === "add_tag" || action.type === "remove_tag" ? "标签名称" : "字段名称"
}
/>
</div>
<div className="space-y-2">
<Label></Label>
<Input
value={action.value}
onChange={(e) => updateAction(index, "value", e.target.value)}
placeholder="输入值"
/>
</div>
</div>
</div>
))}
</div>
</TabsContent>
<TabsContent value="schedule" className="space-y-4">
<h3 className="text-lg font-medium"></h3>
<div className="space-y-4">
<div className="space-y-2">
<Label></Label>
<Select
value={rule.schedule?.type || "immediate"}
onValueChange={(value) =>
setRule({
...rule,
schedule: { ...rule.schedule, type: value as any },
})
}
>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="immediate"></SelectItem>
<SelectItem value="scheduled"></SelectItem>
<SelectItem value="recurring"></SelectItem>
</SelectContent>
</Select>
</div>
{rule.schedule?.type === "scheduled" && (
<div className="space-y-2">
<Label></Label>
<Input
type="datetime-local"
value={rule.schedule.startTime || ""}
onChange={(e) =>
setRule({
...rule,
schedule: { ...rule.schedule, startTime: e.target.value },
})
}
/>
</div>
)}
{rule.schedule?.type === "recurring" && (
<div className="space-y-2">
<Label></Label>
<Select
value={rule.schedule.interval || "daily"}
onValueChange={(value) =>
setRule({
...rule,
schedule: { ...rule.schedule, interval: value },
})
}
>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="hourly"></SelectItem>
<SelectItem value="daily"></SelectItem>
<SelectItem value="weekly"></SelectItem>
<SelectItem value="monthly"></SelectItem>
</SelectContent>
</Select>
</div>
)}
</div>
</TabsContent>
</Tabs>
<Separator className="my-6" />
{validationErrors.length > 0 && (
<Alert className="mb-4">
<AlertCircle className="h-4 w-4" />
<AlertDescription>
<ul className="list-disc list-inside">
{validationErrors.map((error, index) => (
<li key={index}>{error}</li>
))}
</ul>
</AlertDescription>
</Alert>
)}
{testResults && (
<Alert className="mb-4">
<TestTube className="h-4 w-4" />
<AlertDescription>
<div className="space-y-1">
<p>
<strong>:</strong> {testResults.matchedUsers}
</p>
<p>
<strong>:</strong> {testResults.estimatedImpact}
</p>
<p>
<strong>:</strong> {testResults.executionTime}
</p>
</div>
</AlertDescription>
</Alert>
)}
<div className="flex items-center justify-between">
<div className="flex items-center space-x-2">
<Button variant="outline" onClick={handleTest} disabled={isLoading}>
<TestTube className="h-4 w-4 mr-2" />
{isLoading ? "测试中..." : "测试规则"}
</Button>
</div>
<div className="flex items-center space-x-2">
<Button variant="outline" onClick={onCancel}>
</Button>
<Button onClick={handleSave} disabled={isLoading}>
<Save className="h-4 w-4 mr-2" />
</Button>
</div>
</div>
</CardContent>
</Card>
)
}
interface TagRule {
id: string
name: string
description: string
conditions: RuleCondition[]
actions: {
addTags: string[]
removeTags