From 00a44859a673b388e1dca5f54c4ecaffc5fee30e Mon Sep 17 00:00:00 2001
From: 1 <1@123>
Date: 星期四, 19 三月 2026 10:21:08 +0800
Subject: [PATCH] lsh#0:新增、更新、解禁(只要调用了更新,就代表非禁用了)  1:禁用

---
 rsf-admin/src/page/system/aiPrompt/AiPromptList.jsx |  229 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 229 insertions(+), 0 deletions(-)

diff --git a/rsf-admin/src/page/system/aiPrompt/AiPromptList.jsx b/rsf-admin/src/page/system/aiPrompt/AiPromptList.jsx
new file mode 100644
index 0000000..325b6dc
--- /dev/null
+++ b/rsf-admin/src/page/system/aiPrompt/AiPromptList.jsx
@@ -0,0 +1,229 @@
+import React, { useMemo, useState } from "react";
+import {
+    FilterButton,
+    List,
+    SearchInput,
+    SelectInput,
+    TextInput,
+    TopToolbar,
+    useDelete,
+    useListContext,
+    useNotify,
+    useRefresh,
+} from "react-admin";
+import {
+    Box,
+    Button,
+    Card,
+    CardActions,
+    CardContent,
+    Chip,
+    CircularProgress,
+    Divider,
+    Grid,
+    Stack,
+    Typography,
+} from "@mui/material";
+import AddRoundedIcon from "@mui/icons-material/AddRounded";
+import DeleteOutlineOutlinedIcon from "@mui/icons-material/DeleteOutlineOutlined";
+import EditOutlinedIcon from "@mui/icons-material/EditOutlined";
+import VisibilityOutlinedIcon from "@mui/icons-material/VisibilityOutlined";
+import MyExportButton from "@/page/components/MyExportButton";
+import AiPromptForm from "./AiPromptForm";
+import AiConfigDialog from "../aiShared/AiConfigDialog";
+
+const filters = [
+    <SearchInput source="condition" alwaysOn />,
+    <TextInput source="code" label="缂栫爜" />,
+    <TextInput source="scene" label="鍦烘櫙" />,
+    <SelectInput
+        source="status"
+        label="鐘舵��"
+        choices={[
+            { id: "1", name: "common.enums.statusTrue" },
+            { id: "0", name: "common.enums.statusFalse" },
+        ]}
+    />,
+];
+
+const defaultValues = {
+    code: "home.default",
+    scene: "home",
+    status: 1,
+};
+
+const truncateText = (value, max = 120) => {
+    if (!value) {
+        return "--";
+    }
+    return value.length > max ? `${value.slice(0, max)}...` : value;
+};
+
+const AiPromptCards = ({ onView, onEdit, onDelete, deleting }) => {
+    const { data, isLoading } = useListContext();
+    const records = useMemo(() => (Array.isArray(data) ? data : []), [data]);
+
+    if (isLoading) {
+        return (
+            <Box display="flex" justifyContent="center" py={8}>
+                <CircularProgress size={28} />
+            </Box>
+        );
+    }
+
+    if (!records.length) {
+        return (
+            <Box px={2} py={6}>
+                <Card variant="outlined" sx={{ p: 3, textAlign: "center", borderStyle: "dashed" }}>
+                    <Typography variant="subtitle1">鏆傛棤 Prompt 閰嶇疆</Typography>
+                    <Typography variant="body2" color="text.secondary" mt={1}>
+                        鏂板缓涓�寮� Prompt 鍗$墖鍚庯紝AI 瀵硅瘽浼氬姩鎬佸姞杞借繖閲岀殑鍐呭銆�
+                    </Typography>
+                </Card>
+            </Box>
+        );
+    }
+
+    return (
+        <Box px={2} py={2}>
+            <Grid container spacing={2}>
+                {records.map((record) => (
+                    <Grid item xs={12} md={6} xl={4} key={record.id}>
+                        <Card
+                            variant="outlined"
+                            sx={{
+                                height: "100%",
+                                borderRadius: 3,
+                                boxShadow: "0 8px 24px rgba(15, 23, 42, 0.06)",
+                            }}
+                        >
+                            <CardContent sx={{ pb: 1.5 }}>
+                                <Stack direction="row" justifyContent="space-between" alignItems="flex-start" spacing={1}>
+                                    <Box>
+                                        <Typography variant="h6" sx={{ mb: 0.5 }}>
+                                            {record.name}
+                                        </Typography>
+                                        <Typography variant="body2" color="text.secondary">
+                                            {record.code || "--"}
+                                        </Typography>
+                                    </Box>
+                                    <Chip
+                                        size="small"
+                                        color={record.statusBool ? "success" : "default"}
+                                        label={record.statusBool ? "鍚敤" : "鍋滅敤"}
+                                    />
+                                </Stack>
+                                <Stack direction="row" spacing={1} flexWrap="wrap" useFlexGap mt={1.5}>
+                                    <Chip size="small" variant="outlined" label={`Scene: ${record.scene || "--"}`} />
+                                </Stack>
+                                <Divider sx={{ my: 1.5 }} />
+                                <Typography variant="caption" color="text.secondary">System Prompt</Typography>
+                                <Typography variant="body2" sx={{ mt: 0.5 }}>
+                                    {truncateText(record.systemPrompt)}
+                                </Typography>
+                                <Typography variant="caption" color="text.secondary" display="block" mt={1.5}>
+                                    User Prompt Template
+                                </Typography>
+                                <Typography variant="body2">{truncateText(record.userPromptTemplate, 100)}</Typography>
+                            </CardContent>
+                            <CardActions sx={{ px: 2, pb: 2, pt: 0, justifyContent: "space-between" }}>
+                                <Stack direction="row" spacing={1}>
+                                    <Button size="small" startIcon={<VisibilityOutlinedIcon />} onClick={() => onView(record.id)}>
+                                        璇︽儏
+                                    </Button>
+                                    <Button size="small" startIcon={<EditOutlinedIcon />} onClick={() => onEdit(record.id)}>
+                                        缂栬緫
+                                    </Button>
+                                </Stack>
+                                <Button
+                                    size="small"
+                                    color="error"
+                                    startIcon={<DeleteOutlineOutlinedIcon />}
+                                    onClick={() => onDelete(record)}
+                                    disabled={deleting}
+                                >
+                                    鍒犻櫎
+                                </Button>
+                            </CardActions>
+                        </Card>
+                    </Grid>
+                ))}
+            </Grid>
+        </Box>
+    );
+};
+
+const AiPromptList = () => {
+    const notify = useNotify();
+    const refresh = useRefresh();
+    const [deleteOne, { isPending: deleting }] = useDelete();
+    const [dialogState, setDialogState] = useState({ open: false, mode: "create", recordId: null });
+
+    const openDialog = (mode, recordId = null) => setDialogState({ open: true, mode, recordId });
+    const closeDialog = () => setDialogState({ open: false, mode: "create", recordId: null });
+
+    const handleDelete = (record) => {
+        if (!record?.id || !window.confirm(`纭鍒犻櫎鈥�${record.name}鈥濆悧锛焋)) {
+            return;
+        }
+        deleteOne(
+            "aiPrompt",
+            { id: record.id },
+            {
+                onSuccess: () => {
+                    notify("鍒犻櫎鎴愬姛");
+                    refresh();
+                },
+                onError: (error) => {
+                    notify(error?.message || "鍒犻櫎澶辫触", { type: "error" });
+                },
+            }
+        );
+    };
+
+    const dialogTitle = {
+        create: "鏂板缓 Prompt",
+        edit: "缂栬緫 Prompt",
+        show: "鏌ョ湅 Prompt 璇︽儏",
+    }[dialogState.mode];
+
+    return (
+        <>
+            <List
+                title="menu.aiPrompt"
+                filters={filters}
+                sort={{ field: "create_time", order: "desc" }}
+                actions={(
+                    <TopToolbar>
+                        <FilterButton />
+                        <Button variant="contained" startIcon={<AddRoundedIcon />} onClick={() => openDialog("create")}>
+                            鏂板缓
+                        </Button>
+                        <MyExportButton />
+                    </TopToolbar>
+                )}
+            >
+                <AiPromptCards
+                    onView={(id) => openDialog("show", id)}
+                    onEdit={(id) => openDialog("edit", id)}
+                    onDelete={handleDelete}
+                    deleting={deleting}
+                />
+            </List>
+            <AiConfigDialog
+                open={dialogState.open}
+                mode={dialogState.mode}
+                title={dialogTitle}
+                resource="aiPrompt"
+                recordId={dialogState.recordId}
+                defaultValues={defaultValues}
+                maxWidth="lg"
+                onClose={closeDialog}
+            >
+                <AiPromptForm readOnly={dialogState.mode === "show"} />
+            </AiConfigDialog>
+        </>
+    );
+};
+
+export default AiPromptList;

--
Gitblit v1.9.1