AI实施提示词_辅侦工具箱.md
辅侦工具箱 · 全量页面实施提示词
以下为所有页面的统一实施指南。请逐页阅读 docs 目录下的需求文档,按本提示词执行前后端实现。
一、项目技术栈
| 层级 | 技术选型 |
|---|---|
| 前端框架 | Next.js 14 (App Router),TypeScript,Tailwind CSS,shadcn/ui |
| 前端 UI 库 | lucide-react(图标),@/components/ui/*(Button, Input, Select, Dialog, Table 等) |
| 后端框架 | FastAPI + SQLAlchemy + Pydantic |
| 数据库 | PostgreSQL(通过 psycopg2 / asyncpg) |
| 接口规范 | RESTful,Bearer Token 认证,统一 BaseResponse { code, message, data } |
| 代码风格 | 中文注释,模块化组件,hooks 抽离业务逻辑 |
二、公共文件规范(所有页面必须遵循)
2.1 数据库表 → setup.sql
文件路径:backend/scripts/setup.sql
每张表统一格式:
-- 表名:xx
CREATE TABLE IF NOT EXISTS tb_xx (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL COMMENT '姓名',
id_card VARCHAR(18) UNIQUE COMMENT '身份证号',
status VARCHAR(20) DEFAULT '待查询' COMMENT '状态:待查询/查询成功/查询失败/查无结果',
creator_id INTEGER REFERENCES tb_user(id),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
is_deleted BOOLEAN DEFAULT FALSE
);
-- 创建索引
CREATE INDEX IF NOT EXISTS idx_xx_id_card ON tb_xx(id_card);
CREATE INDEX IF NOT EXISTS idx_xx_status ON tb_xx(status);
CREATE INDEX IF NOT EXISTS idx_xx_creator ON tb_xx(creator_id);
-- 初始数据(可选)
-- INSERT INTO tb_xx (...) VALUES (...);
通用字段规则(除非文档明确说没有):
id SERIAL PRIMARY KEY— 必有created_at/updated_at— 必有creator_id INTEGER REFERENCES tb_user(id)— 必有(记录创建人)is_deleted BOOLEAN DEFAULT FALSE— 逻辑删除标志
2.2 后端 Schema → backend/app/schemas/xx.py
from pydantic import BaseModel, Field
from typing import Optional
from datetime import datetime
class XXBase(BaseModel):
"""共享字段"""
name: Optional[str] = None
class XXCreate(XXBase):
"""创建入参"""
name: str
class XXUpdate(XXBase):
"""更新入参"""
pass
class XXItem(XXBase):
"""列表/详情返回"""
id: int
status: str
creator_id: Optional[int]
created_at: Optional[datetime]
updated_at: Optional[datetime]
class Config:
from_attributes = True
2.3 后端 CRUD → backend/app/crud/xx.py
from sqlalchemy.orm import Session
from app.models.xx import XX as ModelXX
from app.schemas.xx import XXCreate, XXUpdate
from typing import List, Optional, Tuple
def create_xx(db: Session, obj: XXCreate, creator_id: int) -> ModelXX:
db_obj = ModelXX(**obj.model_dump(), creator_id=creator_id)
db.add(db_obj)
db.commit()
db.refresh(db_obj)
return db_obj
def get_xx_list(db: Session, skip: int = 0, limit: int = 20, **filters) -> Tuple[List[ModelXX], int]:
query = db.query(ModelXX).filter(ModelXX.is_deleted == False)
for k, v in filters.items():
if v is not None:
query = query.filter(getattr(ModelXX, k) == v)
total = query.count()
items = query.order_by(ModelXX.id.desc()).offset(skip).limit(limit).all()
return items, total
def get_xx_by_id(db: Session, id: int) -> Optional[ModelXX]:
return db.query(ModelXX).filter(ModelXX.id == id, ModelXX.is_deleted == False).first()
def update_xx(db: Session, id: int, obj: XXUpdate) -> Optional[ModelXX]:
db_obj = get_xx_by_id(db, id)
if not db_obj:
return None
for k, v in obj.model_dump(exclude_unset=True).items():
setattr(db_obj, k, v)
db.commit()
db.refresh(db_obj)
return db_obj
def delete_xx(db: Session, id: int) -> bool:
db_obj = get_xx_by_id(db, id)
if not db_obj:
return False
db_obj.is_deleted = True
db.commit()
return True
2.4 后端路由 → backend/app/api/xx.py
from fastapi import APIRouter, Depends, Query
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.core.security import get_current_user
from app.schemas.xx import XXCreate, XXUpdate, XXItem
from app.crud import xx as crud_xx
from typing import List, Optional
router = APIRouter(prefix="/xx", tags=["XX模块"])
@router.get("", response_model=dict)
def list_xx(
page: int = Query(1, ge=1),
page_size: int = Query(20, ge=1, le=100),
status: Optional[str] = None,
keyword: Optional[str] = None,
db: Session = Depends(get_db),
user = Depends(get_current_user),
):
skip = (page - 1) * page_size
items, total = crud_xx.get_xx_list(db, skip=skip, limit=page_size, status=status, keyword=keyword)
return success({
"items": [XXItem.model_validate(i) for i in items],
"total": total, "page": page, "page_size": page_size
})
@router.get("/{id}", response_model=dict)
def get_xx(id: int, db: Session = Depends(get_db), user = Depends(get_current_user)):
obj = crud_xx.get_xx_by_id(db, id)
if not obj:
return error("记录不存在")
return success(XXItem.model_validate(obj))
@router.post("", response_model=dict)
def create_xx(body: XXCreate, db: Session = Depends(get_db), user = Depends(get_current_user)):
obj = crud_xx.create_xx(db, body, creator_id=user["id"])
return success(XXItem.model_validate(obj))
@router.put("/{id}", response_model=dict)
def update_xx(id: int, body: XXUpdate, db: Session = Depends(get_db), user = Depends(get_current_user)):
obj = crud_xx.update_xx(db, id, body)
if not obj:
return error("记录不存在")
return success(XXItem.model_validate(obj))
@router.delete("/{id}", response_model=dict)
def delete_xx(id: int, db: Session = Depends(get_db), user = Depends(get_current_user)):
ok = crud_xx.delete_xx(db, id)
if not ok:
return error("删除失败")
return success({"deleted": True})
注册路由到 main.py:
from app.api import xx
router.include_router(xx.router)
2.5 前端类型 → features/xx/types.ts
export interface XXItem {
id: number;
name: string;
status: string;
creator_id?: number;
created_at?: string;
updated_at?: string;
}
export interface XXFilters {
keyword?: string;
status?: string;
id_card?: string;
page?: number;
page_size?: number;
}
export interface XXListResponse {
items: XXItem[];
total: number;
page: number;
page_size: number;
}
2.6 前端 API 层 → features/xx/api.ts
import { api } from '@/utils/api';
export const xxApi = {
list: (params: Record<string, any>) =>
api.get<XXListResponse>('/xx', { headers: { params } }),
get: (id: number) =>
api.get<XXItem>(`/xx/${id}`),
create: (body: Partial<XXItem>) =>
api.post<XXItem>('/xx', body),
update: (id: number, body: Partial<XXItem>) =>
api.put<XXItem>(`/xx/${id}`, body),
delete: (id: number) =>
api.delete<void>(`/xx/${id}`),
};
2.7 前端 Feature 入口 → features/xx/index.tsx
"use client";
import { XXFeature } from './components/XXFeature';
export { XXFeature };
三、三种页面类型 — 实施模式
类型 A:主界面(主列表页)
识别特征:文档中有「数据展示区」「搜索筛选」「数据表格」「分页」「操作按钮组」
对应路由:app/page.tsx 中的 renderContent() 里添加:
if (activeItem === "页面标题") return <XXFeature />;
Feature 组件结构(features/xx/components/XXFeature.tsx):
"use client";
import { useState } from 'react';
import { XXSearchFilter } from './XXSearchFilter';
import { XXTable } from './XXTable';
import { XXDialog } from './XXDialog';
import { XXFormDialog } from './XXFormDialog';
import { api } from '@/utils/api';
import { XXItem, XXFilters } from '../types';
export function XXFeature() {
const [filters, setFilters] = useState<XXFilters>({});
const [selectedIds, setSelectedIds] = useState<number[]>([]);
const [dialogOpen, setDialogOpen] = useState(false);
const [editId, setEditId] = useState<number | null>(null);
const [formOpen, setFormOpen] = useState(false);
const handleSearch = (f: XXFilters) => setFilters(f);
const handleReset = () => setFilters({});
const handleEdit = (id: number) => { setEditId(id); setFormOpen(true); };
const handleDelete = async (id: number) => { /* ... */ };
return (
<div className="flex flex-col h-full">
<XXSearchFilter onSearch={handleSearch} onReset={handleReset} />
<XXTable
filters={filters}
selectedIds={selectedIds}
onSelectionChange={setSelectedIds}
onEdit={handleEdit}
onDelete={handleDelete}
onRefresh={() => {}} // passed as prop, triggers table reload
/>
</div>
);
}
搜索筛选组件(XXSearchFilter.tsx):
"use client";
import { useState } from 'react';
import { Search, RotateCcw } from 'lucide-react';
import { Button } from '@/components/ui/Button';
import { Input } from '@/components/ui/Input';
import { Select } from '@/components/ui/Select';
import { XXFilters } from '../types';
const STATUS_OPTIONS = [
{ label: '待查询', value: '待查询' },
{ label: '查询成功', value: '查询成功' },
// ... 按文档中的审核/状态字段填充
];
interface Props {
onSearch: (f: XXFilters) => void;
onReset: () => void;
}
export function XXSearchFilter({ onSearch, onReset }: Props) {
const [f, setF] = useState<XXFilters>({});
return (
<div className="bg-white px-4 py-3 border-b border-border-custom space-y-2">
<div className="flex items-center flex-wrap gap-2">
{/* 身份证筛选 — 仅当文档有「身份证」列时添加 */}
<div className="flex items-center space-x-1">
<span className="text-[12px] text-text-secondary w-14">身份证</span>
<Input className="h-8 w-44 text-[12px]" placeholder="请输入身份证"
value={f.id_card || ''} onChange={e => setF({...f, id_card: e.target.value})} />
</div>
{/* 关键词筛选 */}
<div className="flex items-center space-x-1">
<span className="text-[12px] text-text-secondary w-14">关键词</span>
<Input className="h-8 w-36 text-[12px]" placeholder="请输入"
value={f.keyword || ''} onChange={e => setF({...f, keyword: e.target.value})} />
</div>
{/* 状态筛选 — 仅当文档有「审核状态」「查询状态」列时添加 */}
<div className="flex items-center space-x-1">
<span className="text-[12px] text-text-secondary w-14">审核状态</span>
<Select className="h-8 w-32 text-[12px]" options={STATUS_OPTIONS}
value={f.status || ''} onChange={v => setF({...f, status: v})} placeholder="请选择" />
</div>
{/* 查询/重置按钮 */}
<div className="flex items-center space-x-2 ml-auto">
<Button variant="primary" size="sm" className="h-8" onClick={() => onSearch(f)}>
<Search className="w-3.5 h-3.5 mr-1" />查询
</Button>
<Button variant="outline" size="sm" className="h-8" onClick={() => { setF({}); onReset(); }}>
<RotateCcw className="w-3.5 h-3.5 mr-1" />重置
</Button>
</div>
</div>
</div>
);
}
表格组件(XXTable.tsx):
"use client";
import { useState, useEffect } from 'react';
import { ChevronLeft, ChevronRight, RotateCw, Trash2, Eye } from 'lucide-react';
import { Button } from '@/components/ui/Button';
import { Checkbox } from '@/components/ui/Checkbox';
import { XXItem, XXFilters, XXListResponse } from '../types';
import { xxApi } from '../api';
const STATUS_COLORS: Record<string, string> = {
'查询成功': 'bg-green-100 text-green-700',
'查询失败': 'bg-red-100 text-red-700',
'待查询': 'bg-yellow-100 text-yellow-700',
// ... 按实际状态值填充
};
interface Props {
filters: XXFilters;
selectedIds: number[];
onSelectionChange: (ids: number[]) => void;
onEdit: (id: number) => void;
onDelete: (id: number) => void;
onRefresh: () => void;
}
export function XXTable({ filters, selectedIds, onSelectionChange, onEdit, onDelete, onRefresh }: Props) {
const [data, setData] = useState<XXListResponse>({ items: [], total: 0, page: 1, page_size: 10 });
const [loading, setLoading] = useState(false);
const [page, setPage] = useState(1);
const PAGE_SIZE = 10;
const load = async () => {
setLoading(true);
try {
const res = await xxApi.list({ ...filters, page, page_size: PAGE_SIZE });
setData(res);
} finally {
setLoading(false);
}
};
useEffect(() => { load(); }, [filters, page]);
const toggleAll = (checked: boolean) => {
if (checked) onSelectionChange(data.items.map(i => i.id));
else onSelectionChange([]);
};
const toggleOne = (id: number) => {
if (selectedIds.includes(id)) onSelectionChange(selectedIds.filter(x => x !== id));
else onSelectionChange([...selectedIds, id]);
};
const handleBatchDelete = async () => {
if (!selectedIds.length) return;
if (!confirm(`确认删除 ${selectedIds.length} 条记录?`)) return;
await Promise.all(selectedIds.map(id => xxApi.delete(id)));
onSelectionChange([]);
load();
};
const columns = [
{ label: '序号', width: 60 },
{ label: '身份证', dataIndex: 'id_card', width: 180 },
{ label: '姓名', dataIndex: 'name', width: 120 },
{ label: '状态', dataIndex: 'status', width: 120, render: (v: string) =>
<span className={`px-2 py-0.5 rounded text-[11px] font-medium ${STATUS_COLORS[v] || 'bg-gray-100 text-gray-600'}`}>{v}</span> },
{ label: '创建时间', dataIndex: 'created_at', width: 180 },
{ label: '操作', width: 120, render: (_: any, row: XXItem) => (
<div className="flex items-center space-x-2">
<button onClick={() => onEdit(row.id)} className="text-primary-active hover:underline text-[12px]">编辑</button>
<button onClick={() => onDelete(row.id)} className="text-red-500 hover:underline text-[12px]">删除</button>
</div>
)},
];
return (
<div className="flex-1 overflow-auto p-4 space-y-3">
{/* 批量操作栏 */}
{selectedIds.length > 0 && (
<div className="bg-blue-50 border border-blue-200 rounded px-4 py-2 flex items-center justify-between">
<span className="text-[12px] text-blue-700">已选中 {selectedIds.length} 项</span>
<div className="flex space-x-2">
<Button variant="outline" size="sm" className="h-7 text-[12px]"
onClick={handleBatchDelete}>
<Trash2 className="w-3.5 h-3.5 mr-1" />批量删除
</Button>
</div>
</div>
)}
{/* 数据表格 */}
<div className="bg-white rounded border border-border-custom overflow-hidden">
<table className="w-full text-[13px]">
<thead className="bg-[#F7F8FA]">
<tr>
<th className="px-3 py-2.5 text-left w-10">
<Checkbox checked={selectedIds.length === data.items.length && data.items.length > 0}
onChange={toggleAll} />
</th>
{columns.map(col => (
<th key={col.label} className="px-3 py-2.5 text-left text-[#999] font-normal"
style={{ width: col.width }}>
{col.label}
</th>
))}
</tr>
</thead>
<tbody>
{loading ? (
<tr><td colSpan={columns.length + 1} className="text-center py-10 text-[#999]">加载中...</td></tr>
) : data.items.length === 0 ? (
<tr><td colSpan={columns.length + 1} className="text-center py-10 text-[#999]">暂无数据</td></tr>
) : data.items.map((row, idx) => (
<tr key={row.id} className="border-t border-border-custom hover:bg-slate-50">
<td className="px-3 py-2.5"><Checkbox checked={selectedIds.includes(row.id)} onChange={() => toggleOne(row.id)} /></td>
{columns.map(col => (
<td key={col.label} className="px-3 py-2.5 text-text-primary">
{col.render ? col.render((row as any)[col.dataIndex!], row) : (row as any)[col.dataIndex!]}
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
{/* 分页 */}
<div className="flex items-center justify-between px-1">
<span className="text-[12px] text-text-secondary">共 {data.total} 条</span>
<div className="flex items-center space-x-1">
<Button variant="outline" size="sm" className="h-7 w-7 p-0"
disabled={page <= 1} onClick={() => setPage(p => p - 1)}>
<ChevronLeft className="w-4 h-4" />
</Button>
<span className="text-[12px] text-text-primary px-2">{page}</span>
<Button variant="outline" size="sm" className="h-7 w-7 p-0"
disabled={page * PAGE_SIZE >= data.total} onClick={() => setPage(p => p + 1)}>
<ChevronRight className="w-4 h-4" />
…21036 tokens truncated…按钮
关闭(次按钮)、确定(主按钮)
## 3. 表格/列表类组件
无表头、数据行、分页、筛选、行操作按钮等表格相关组件
## 4. 静态文本展示元素
弹窗标题「优先执行」、任务状态标签文字、任务状态值「查询中」、确认提示文案、背景水印文本
## 5. 缺失组件说明
无顶部全局导航、左侧树形侧边菜单、页面标签、筛选表单、批量操作按钮、数据表格、分页控件、图片预览、文件上传区域、页面底部状态栏信息区、新增/编辑/删除/查询类全局功能按钮