diff --git a/Project/fonrey/DATA_MODEL/DATA_MODEL文档要求.md b/Project/fonrey/DATA_MODEL/DATA_MODEL文档要求.md new file mode 100644 index 00000000..45a36522 --- /dev/null +++ b/Project/fonrey/DATA_MODEL/DATA_MODEL文档要求.md @@ -0,0 +1,262 @@ +`DATA_MODEL.md` 的核心目标是:**让 AI 在触碰任何数据相关代码时,都能理解业务语义,而不只是看到一堆字段名。** + +--- + +### 必须包含的内容 + +#### 1. 领域概览(Domain Overview) + +用业务语言(不是技术语言)描述核心概念和它们的关系。这是 AI 理解"为什么"的基础。 + +md + +```md +## Domain Overview + +This is a **multi-tenant** project management tool. + +Core concepts: +- **Workspace**: The top-level container, maps to a paying customer (company) +- **Project**: Lives inside a Workspace, has a lifecycle (draft → active → archived) +- **Task**: The atomic unit of work, always belongs to a Project +- **Member**: A User's role within a specific Workspace (not global) + +Key business rules: +- A User can belong to multiple Workspaces with different roles +- Deleting a Project soft-deletes all its Tasks (never hard delete) +- Only Workspace `owner` or `admin` can invite new Members +``` + +--- + +#### 2. 实体关系图(Entity Relationship) + +用文字或 ASCII 图表达清楚关系,不要依赖读者去脑补。 + +md + +```md +## Entity Relationships + +Workspace (1) ──── (N) Project +Workspace (1) ──── (N) Member +Member (N) ──── (1) User ← same User, different roles per Workspace +Project (1) ──── (N) Task +Task (N) ──── (1) Member ← assignee +Task (1) ──── (N) Comment +Task (N) ──── (N) Tag ← via task_tags join table +``` + +--- + +#### 3. 完整 Schema 定义(Schema Definition) + +每个表都需要:字段 + 类型 + 约束 + **业务注释**。注释是给 AI 的关键上下文。 + +md + +```md +## Schema + +### workspaces +| Column | Type | Constraints | Notes | +|--------------|-------------|-------------------|--------------------------------| +| id | uuid | PK, default gen | | +| slug | text | UNIQUE, NOT NULL | URL identifier, immutable after creation | +| name | text | NOT NULL | | +| plan | text | NOT NULL | enum: 'free' | 'pro' | 'enterprise' | +| created_at | timestamptz | NOT NULL, default now() | | +| deleted_at | timestamptz | nullable | soft delete, filter WHERE deleted_at IS NULL | + +### members +| Column | Type | Constraints | Notes | +|--------------|-------------|-------------------|--------------------------------| +| id | uuid | PK | | +| workspace_id | uuid | FK → workspaces.id, CASCADE DELETE | | +| user_id | uuid | FK → users.id | | +| role | text | NOT NULL | enum: 'owner' \| 'admin' \| 'member' \| 'viewer' | +| invited_by | uuid | FK → members.id, nullable | null = founding owner | +| joined_at | timestamptz | nullable | null = invitation pending | + +-- UNIQUE(workspace_id, user_id) — one membership per workspace per user +``` + +--- + +#### 4. 枚举与常量(Enums & Constants) + +把所有枚举值集中在一处,AI 就不会自己发明状态值。 + +md + +```md +## Enums & Constants + +### Task Status (ordered, represents workflow progression) +pending → in_progress → in_review → done → cancelled + +Rules: +- Only forward transitions are allowed (no reopening cancelled tasks) +- `done` and `cancelled` are terminal states +- Changing status logs an entry in task_activity + +### Member Role Permissions +| Action | owner | admin | member | viewer | +|---------------------|-------|-------|--------|--------| +| Invite members | ✅ | ✅ | ❌ | ❌ | +| Delete project | ✅ | ❌ | ❌ | ❌ | +| Create tasks | ✅ | ✅ | ✅ | ❌ | +| Comment on tasks | ✅ | ✅ | ✅ | ✅ | +``` + +--- + +#### 5. 索引策略(Indexes) + +告诉 AI 哪些查询是热路径,避免它写出全表扫描的代码。 + +md + +```md +## Indexes + +-- tasks is the most queried table, optimize for these patterns: +CREATE INDEX idx_tasks_project_status ON tasks(project_id, status) WHERE deleted_at IS NULL; +CREATE INDEX idx_tasks_assignee ON tasks(assignee_id) WHERE deleted_at IS NULL; +CREATE INDEX idx_members_user ON members(user_id); -- "get all workspaces for a user" + +-- Avoid: never query tasks without a project_id filter +-- Avoid: never do SELECT * on tasks, always select specific columns +``` + +--- + +#### 6. 软删除约定(Soft Delete Convention) + +如果使用软删除,必须明确说明规则,否则 AI 会写出漏掉过滤条件的查询。 + +md + +```md +## Soft Delete Convention + +Tables with soft delete: workspaces, projects, tasks + +Rules: +- ALL queries MUST include `WHERE deleted_at IS NULL` unless explicitly retrieving deleted records +- Use `deletedAt: new Date()` to soft delete, never use DELETE SQL +- Cascading: deleting a Project sets deleted_at on all its Tasks in the same transaction +- Deleted records are purged by a cron job after 30 days (hard delete) + +⚠️ AI Note: Never generate a query on these tables without the soft delete filter. +``` + +--- + +#### 7. 多租户隔离规则(Multi-tenancy Rules) + +这是安全的核心,必须让 AI 理解每次查询都要带租户过滤。 + +md + +```md +## Multi-tenancy & Data Isolation + +This is a **workspace-scoped** multi-tenant system. + +Rules: +- EVERY query involving projects, tasks, members MUST be scoped by workspace_id +- Never query tasks directly by id alone — always join through project → workspace +- The workspace_id must come from the authenticated session, never from user input +- Row Level Security (RLS) is enabled on Supabase for all tenant tables + +Correct pattern: + SELECT * FROM tasks + JOIN projects ON tasks.project_id = projects.id + WHERE projects.workspace_id = :workspaceId ← always present + AND tasks.id = :taskId + +Wrong pattern (security hole): + SELECT * FROM tasks WHERE id = :taskId ← missing tenant scope +``` + +--- + +#### 8. 核心查询模式(Common Query Patterns) + +把最常用的查询写出来,AI 会直接复用,而不是重新发明。 + +md + +````md +## Common Query Patterns + +### Get tasks for a project (with assignee info) +```sql +SELECT t.*, m.user_id, u.name as assignee_name +FROM tasks t +LEFT JOIN members m ON t.assignee_id = m.id +LEFT JOIN users u ON m.user_id = u.id +WHERE t.project_id = :projectId + AND t.deleted_at IS NULL +ORDER BY t.created_at DESC; +``` + +### Check if user has permission in workspace +```sql +SELECT role FROM members +WHERE workspace_id = :workspaceId + AND user_id = :userId + AND joined_at IS NOT NULL; -- pending invitations don't count +``` +```` + +--- + +#### 9. 明确禁止的操作(Forbidden Operations) + +md + +```md +## Forbidden Operations + +- ❌ Never hard DELETE on workspaces, projects, or tasks — use soft delete +- ❌ Never UPDATE a task's status by skipping intermediate states +- ❌ Never expose internal UUIDs in URLs — use slugs for workspaces/projects +- ❌ Never store user PII (email, name) in tasks or comments — always join from users table +- ❌ Never write a migration that drops a column without a deprecation period +``` + +--- + +#### 10. 数据迁移约定(Migration Convention) + +md + +```md +## Migration Convention + +- Migration tool: Drizzle Kit +- File naming: `0001_create_workspaces.ts`, sequential, never rename +- Every migration must be reversible (include `down` function) +- Never edit a migration that has been merged to main +- Backfill scripts go in /scripts, not in migrations +``` + +--- + +### 内容优先级总结 + +|优先级|内容|为什么关键| +|---|---|---| +|🔴 必须|领域概览 + 业务规则|AI 需要理解"为什么"才能做正确取舍| +|🔴 必须|完整 Schema + 字段注释|防止字段命名歧义和类型错误| +|🔴 必须|软删除 + 多租户规则|安全漏洞和数据污染的高发区| +|🟡 重要|枚举常量 + 状态机|防止 AI 自己发明状态值| +|🟡 重要|常用查询模式|复用 > 重新发明| +|🟢 加分|索引策略|引导 AI 写出性能友好的查询| +|🟢 加分|迁移约定|保持 schema 演进的可控性| + +--- + +**核心原则**:`DATA_MODEL.md` 写的不是给数据库看的 DDL,而是给 AI 看的**业务契约**。每一个"显而易见"的业务规则,在 AI 眼里都是需要被明确告知的约束。没写的,它都会自己猜。 \ No newline at end of file diff --git a/Project/fonrey/TECH_STACK/TECH_STACK 文档要求.md b/Project/fonrey/TECH_STACK/TECH_STACK 文档要求.md new file mode 100644 index 00000000..c010f983 --- /dev/null +++ b/Project/fonrey/TECH_STACK/TECH_STACK 文档要求.md @@ -0,0 +1,161 @@ +#### 1. 项目概览(Project Overview) + +用 2-3 句话说清楚这是什么项目、核心用途、目标用户。AI 需要这个"北极星"来判断所有技术取舍。 + +md + +```md +## Project Overview +A B2B SaaS invoice management tool. Target users are SMB accountants. +Prioritize reliability and data integrity over flashy UI. +``` + +--- + +#### 2. 核心技术栈(Core Stack) + +每一层都要写清楚,**不要只写框架名,要写版本号和选型原因**。 + +md + +```md +## Core Stack +- Runtime: Node.js 22 (not Bun, not Deno) +- Framework: Next.js 15 (App Router only, never Pages Router) +- Language: TypeScript 5.x, strict mode enabled +- Database: PostgreSQL 16 via Supabase +- ORM: Drizzle ORM (not Prisma) +- Styling: Tailwind CSS v4 + shadcn/ui +- Auth: Clerk +- Deployment: Vercel +``` + +--- + +#### 3. 关键约定(Key Conventions) + +这是 vibe coding 最容易出错的地方,AI 会有自己的"默认习惯",必须显式覆盖。 + +md + +```md +## Key Conventions +- File naming: kebab-case for files, PascalCase for components +- All server actions in /actions, never inline in components +- Use `server components` by default; add 'use client' only when needed +- Environment variables: never hardcode, always use process.env.NEXT_PUBLIC_* +- Error handling: always use Result pattern, never throw in server actions +- No `any` types. No `// @ts-ignore`. +``` + +--- + +#### 4. 目录结构(Directory Structure) + +AI 需要知道把新文件放在哪里,否则它会自己"发明"结构。 + +md + +```md +## Directory Structure +src/ +├── app/ # Next.js routes only, minimal logic +├── components/ # Reusable UI components +│ └── ui/ # shadcn primitives, DO NOT edit +├── actions/ # Server actions +├── lib/ # Utilities and helpers +├── db/ # Drizzle schema and migrations +└── types/ # Global TypeScript types +``` + +--- + +#### 5. 明确禁止的东西(Explicitly Forbidden) + +这是最被忽视但最重要的部分。告诉 AI **不要用什么**,比告诉它用什么更有效。 + +md + +```md +## Do NOT Use +- ❌ `axios` — use native `fetch` +- ❌ `moment.js` — use `date-fns` +- ❌ `useEffect` for data fetching — use server components or React Query +- ❌ `pages/` directory — App Router only +- ❌ `class components` — functional only +- ❌ CSS Modules or styled-components — Tailwind only +- ❌ `console.log` in production code +``` + +--- + +#### 6. 第三方服务与集成(External Services) + +列出已经接入的服务,避免 AI 重复造轮子或引入冲突的 SDK。 + +md + +```md +## External Services +- Payments: Stripe (already configured in /lib/stripe.ts) +- Email: Resend + React Email templates +- File storage: Supabase Storage (not S3) +- Analytics: PostHog +- Error tracking: Sentry +``` + +--- + +#### 7. 代码风格与 Linting(Code Style) + +md + +```md +## Code Style +- Formatter: Prettier (config in .prettierrc) +- Linter: ESLint with eslint-config-next +- Imports: absolute paths via `@/` alias, no relative `../../` +- Prefer `const` over `let`, avoid `var` +- Async/await over `.then()` chains +``` + +--- + +#### 8. 测试策略(Testing, 如果有的话) + +md + +```md +## Testing +- Unit tests: Vitest +- E2E tests: Playwright (critical flows only) +- No snapshot tests +- Test files co-located: `component.test.ts` next to `component.ts` +``` + +--- + +### 一个实用的小技巧 + +在文件开头加一句 AI 专用说明: + +md + +```md +> **For AI assistants**: Read this entire file before writing any code. +> All decisions here are final. Do not suggest alternatives unless asked. +``` + +--- + +### 内容优先级总结 + +|优先级|内容|原因| +|---|---|---| +|🔴 必须|核心技术栈 + 禁止列表|防止 AI 用错库| +|🔴 必须|目录结构 + 文件约定|防止结构混乱| +|🟡 重要|外部服务清单|防止重复实现| +|🟡 重要|关键约定|保持风格一致| +|🟢 加分|测试策略 + 代码风格|提升整体质量| + +**核心原则**:写给 AI 看的文档要比写给人看的**更具体、更强硬、更少歧义**。任何"视情况而定"的描述,AI 都会做出你不想要的选择。 \ No newline at end of file diff --git a/Project/fonrey/UI&UX/UI_SYSTEM文档要求.md b/Project/fonrey/UI&UX/UI_SYSTEM文档要求.md new file mode 100644 index 00000000..3a0252e4 --- /dev/null +++ b/Project/fonrey/UI&UX/UI_SYSTEM文档要求.md @@ -0,0 +1,432 @@ +`UI_SYSTEM.md` 的核心目标是:**让 AI 生成的每一个组件,都像是同一个设计师写的,而不是从五个不同的 UI 库里随机拼凑的。** + +--- + +## 必须包含的内容 + +### 1. 设计哲学(Design Philosophy) + +在写任何具体规则之前,先定义"感觉"。AI 在模糊情况下会回到这里做判断。 + +```md +## Design Philosophy + +**Core aesthetic**: Clean, functional, low-friction. +We build tools, not experiences. Every UI element must earn its place. + +**Principles** (in priority order): +1. **Clarity over cleverness** — if you have to explain the UI, it failed +2. **Density over whitespace** — our users are power users, don't waste screen space +3. **Consistency over novelty** — use existing patterns before inventing new ones +4. **Motion is functional** — animate only to communicate state change, never for decoration + +**Anti-patterns we actively avoid**: +- Skeleton loaders for data that loads in < 300ms (just show a spinner) +- Modal dialogs for destructive actions that are easily reversible +- Infinite scroll (we use pagination, users need to share URLs to specific pages) +- Tooltips on mobile +``` + +--- + +### 2. 设计 Token(Design Tokens) + +这是整个系统的基础。所有颜色、间距、字体都必须来自这里,AI 不能自己发明数值。 + +````md +## Design Tokens + +### Color System +We use CSS variables. NEVER use raw hex values in components. + +**Semantic colors** (use these, not primitives): +```css +--color-bg-base /* page background */ +--color-bg-subtle /* card, sidebar backgrounds */ +--color-bg-muted /* disabled states, placeholders */ + +--color-text-primary /* body text */ +--color-text-secondary /* labels, captions */ +--color-text-disabled /* disabled text */ +--color-text-inverse /* text on dark backgrounds */ + +--color-border /* default borders */ +--color-border-strong /* focused, emphasized borders */ + +--color-accent /* primary actions, links */ +--color-accent-hover /* hover state of accent */ + +--color-success /* confirmations, completed states */ +--color-warning /* non-blocking alerts */ +--color-danger /* destructive actions, errors */ +--color-info /* informational, neutral alerts */ +```` + +**Rule**: If you find yourself writing `text-gray-500`, stop. Map it to a semantic token. + +### Spacing Scale + +We use an 4px base grid. Only use these values: `4px / 8px / 12px / 16px / 24px / 32px / 48px / 64px / 96px` + +In Tailwind: `p-1 / p-2 / p-3 / p-4 / p-6 / p-8 / p-12 / p-16 / p-24` + +Never: `p-5`, `p-7`, `p-9`, `p-10`, `p-11` — these break the grid. + +### Border Radius + +``` +--radius-sm: 4px → rounded-sm (inputs, badges) +--radius-md: 8px → rounded (cards, buttons) ← default +--radius-lg: 12px → rounded-xl (modals, panels) +--radius-full: 9999px → rounded-full (avatars, pills) +``` + +Never mix radius sizes within the same component. + +### Elevation / Shadow + +``` +--shadow-sm → subtle card lift +--shadow-md → dropdowns, popovers +--shadow-lg → modals, dialogs +``` + +Never use `drop-shadow` filter — use `box-shadow` only. + +```` + +--- + +### 3. 字体系统(Typography System) + +```md +## Typography + +**Font stack**: +- UI: `Inter` (loaded via next/font, variable weight) +- Code: `JetBrains Mono` (code blocks, inline code only) +- Never import fonts from Google Fonts directly + +**Type scale** (use only these, no arbitrary sizes): + +| Token | Size | Weight | Line-height | Usage | +|----------------|-------|--------|-------------|--------------------------| +| `text-xs` | 12px | 400 | 1.5 | Labels, badges, metadata | +| `text-sm` | 14px | 400 | 1.5 | Body, secondary content | +| `text-base` | 16px | 400 | 1.6 | Primary body text | +| `text-lg` | 18px | 500 | 1.4 | Section headings | +| `text-xl` | 20px | 600 | 1.3 | Page sub-headings | +| `text-2xl` | 24px | 700 | 1.2 | Page titles | +| `text-3xl` | 30px | 700 | 1.1 | Hero headings only | + +**Rules**: +- Max 2 font sizes per component +- `font-weight: 500` is the minimum for anything interactive (buttons, links) +- Never use `text-3xl` outside of marketing pages +- Line length: max 72 characters for body text (`max-w-prose`) +```` + +--- + +### 4. 核心组件规范(Core Component Specs) + +为每个高频组件定义变体、状态和使用规则。这是 AI 最需要的部分。 + +````md +## Core Component Specs + +### Button + +**Variants**: +| Variant | Use case | Never use for | +|-------------|---------------------------------------|----------------------------| +| `primary` | Single main CTA per view | Destructive actions | +| `secondary` | Secondary actions | Main CTA | +| `ghost` | Toolbar actions, low-priority | Standalone CTAs | +| `danger` | Irreversible destructive actions only | Anything reversible | +| `link` | Navigation only | Form submissions | + +**Sizes**: `sm` (28px h) / `md` (36px h, default) / `lg` (44px h) + +**States** (all must be handled): +- `default` / `hover` / `active` / `focus-visible` / `disabled` / `loading` + +**Loading state rule**: +Show spinner + disable button immediately on click. +Never let the button be clicked twice. +```tsx +// Correct + + +// Wrong — no loading state + +```` + +**Icon buttons**: Always include `aria-label`. Never use icon-only buttons for primary actions. + +--- + +### Form Inputs + +**Anatomy** (always in this order, no exceptions): + +``` +[Label] ← always visible, never placeholder-only +[Input field] +[Helper text] ← optional, describes expected format +[Error message] ← replaces helper text on error +``` + +**States**: `default` / `focus` / `error` / `disabled` / `readonly` + +**Rules**: + +- Label always above input, never to the side (except checkbox/radio) +- Placeholder text is NOT a label — both must exist +- Error messages: specific and actionable ("Enter a valid email" not "Invalid input") +- Required fields: mark with asterisk (*) next to label, explain at top of form +- Never disable a submit button to prevent submission — show errors inline instead + +--- + +### Data Table + +```md +### Table + +**Default behavior**: +- Sticky header on scroll +- Row hover highlight +- Checkbox column for bulk actions (leftmost) +- Actions column (rightmost, visible on row hover only) +- Empty state: illustration + message + CTA (never just "No data") + +**Pagination**: +- Default page size: 25 rows +- Options: 10 / 25 / 50 / 100 +- Always show total count ("Showing 1–25 of 143 results") +- Preserve page position on filter change + +**Column rules**: +- Numbers: right-aligned, monospace font +- Dates: relative time for < 7 days ("2 hours ago"), absolute for older +- Status: always a colored badge, never plain text +- Long text: truncate with tooltip showing full value +``` + +--- + +### Modal / Dialog + +```md +### Modal + +**Size variants**: +| Size | Max-width | Use case | +|-------|-----------|---------------------------| +| `sm` | 400px | Confirmation dialogs | +| `md` | 560px | Forms with < 5 fields | +| `lg` | 720px | Complex forms, previews | +| `xl` | 960px | Multi-step flows | + +**Rules**: +- Always trap focus inside modal +- ESC key always closes (unless unsaved changes → show confirmation) +- Click outside closes (unless form with unsaved changes) +- Never nest modals — use a multi-step flow instead +- Destructive confirm dialogs: danger button on RIGHT, cancel on LEFT +- Never auto-close a modal after async action — wait for user to dismiss +``` + +--- + +### 5. 状态与反馈模式(State & Feedback Patterns) + +````md +## State & Feedback Patterns + +### Loading States +| Duration | Pattern | +|---------------|--------------------------------| +| < 300ms | Nothing (avoid flash of spinner)| +| 300ms – 1s | Inline spinner | +| 1s – 3s | Spinner + "Loading..." | +| > 3s | Progress bar + estimated time | +| Background | Subtle pulsing indicator in nav| + +### Empty States +Every list/table must handle empty state: +```tsx +// Required elements: +// 1. Relevant icon (not a generic "no data" icon) +// 2. Friendly headline ("No tasks yet") +// 3. Explanation of why ("Projects with tasks will appear here") +// 4. CTA if user can fix it ("Create your first task →") +```` + +### Toast Notifications + +|Type|When to use|Duration| +|---|---|---| +|`success`|Async action completed|3s| +|`error`|Action failed, user must retry|persistent| +|`warning`|Completed with caveats|5s| +|`info`|Background process started|3s| + +**Rules**: + +- Max 3 toasts visible at once (queue the rest) +- Never show success toast for page navigations +- Error toasts must include a retry action when possible +- Never use toast for validation errors — show inline instead + +### Skeleton vs Spinner + +- Skeleton: only for content with known layout (profile cards, feed items) +- Spinner: for unknown-shape content, buttons, inline actions +- Never both at the same time in the same view + +```` + +--- + +### 6. 响应式断点(Responsive Breakpoints) + +```md +## Responsive Breakpoints + +**Strategy**: Desktop-first (our users are 85% desktop) + +| Breakpoint | Token | Value | Target | +|------------|--------|--------|--------------------------| +| Desktop | (base) | > 1280px | Primary design target | +| Laptop | `lg` | 1024px | Minor adjustments | +| Tablet | `md` | 768px | Collapsed sidebar | +| Mobile | `sm` | 640px | Single column, no tables | + +**Component-specific rules**: +- Data tables → horizontal scroll on `md` and below +- Sidebar → collapses to bottom nav on `sm` +- Modals → full-screen on `sm` +- Multi-column forms → single column on `md` and below + +**Never**: +- Hide critical functionality on mobile (adapt it, don't remove it) +- Use fixed px widths for layout containers +- Assume touch input on desktop or mouse on mobile +```` + +--- + +### 7. 动效规范(Motion & Animation) + +```md +## Motion & Animation + +**Principle**: Motion communicates state, it doesn't decorate. + +**Duration scale**: +``` + +--duration-fast: 100ms → micro-interactions (checkbox, toggle) --duration-normal: 200ms → most transitions (hover, focus) --duration-slow: 350ms → larger elements (modal, drawer enter) --duration-crawl: 500ms → only for page-level transitions + +``` + +**Easing**: +``` + +--ease-default: cubic-bezier(0.2, 0, 0, 1) → most UI transitions --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1) → playful elements only --ease-linear: linear → progress bars only + +``` + +**What to animate**: +- ✅ Opacity (enter/exit) +- ✅ Transform: translateY (panel slide-in) +- ✅ Max-height (accordion expand) + +**Never animate**: +- ❌ `width` or `height` directly (use `max-height` or `transform`) +- ❌ `top/left/right/bottom` (use `transform: translate`) +- ❌ `box-shadow` on hover (use opacity trick instead) +- ❌ Anything if `prefers-reduced-motion: reduce` +``` + +--- + +### 8. 可访问性基线(Accessibility Baseline) + +```md +## Accessibility (Non-negotiable) + +**Every component must**: +- Meet WCAG 2.1 AA contrast ratios (4.5:1 body, 3:1 large text) +- Be fully keyboard navigable +- Have visible focus indicators (never `outline: none` without replacement) +- Work with screen readers (proper ARIA roles and labels) + +**Required patterns**: +- Icon-only buttons: always `aria-label` +- Form inputs: always `htmlFor` ↔ `id` pairing +- Images: `alt` text always (empty string `""` for decorative images) +- Modals: `role="dialog"`, `aria-modal="true"`, focus trap +- Loading states: `aria-busy="true"` on the loading container +- Error messages: `aria-describedby` linking input to error text + +**Color alone is never enough**: +- Status badges: color + icon + text +- Form errors: color + icon + message below field +- Graphs: color + pattern or label +``` + +--- + +### 9. 禁止模式(Anti-patterns) + +```md +## UI Anti-patterns — Never Do These + +**Layout**: +- ❌ Centering body text wider than 72 characters +- ❌ Full-width buttons on desktop (max-width: 320px) +- ❌ Mixing card and table layouts in the same list view + +**Interaction**: +- ❌ Double-click to perform actions (single click only) +- ❌ Drag-and-drop as the *only* way to reorder +- ❌ Hover-only affordances (invisible until you hover) +- ❌ Auto-submitting forms on change without explicit confirmation + +**Feedback**: +- ❌ Generic error messages ("Something went wrong") +- ❌ Success messages that don't tell the user what happened +- ❌ Blocking UI with a spinner for optimistic actions +- ❌ Alert dialogs (window.alert) — use our Dialog component + +**Content**: +- ❌ Lorem ipsum in any committed code +- ❌ Hardcoded user names or emails in components +- ❌ Placeholder images (use our Avatar initials fallback) +``` + +--- + +## 优先级总结 + +|优先级|内容|为什么关键| +|---|---|---| +|🔴 必须|设计 Token(颜色、间距、圆角)|AI 最容易乱用原始数值| +|🔴 必须|核心组件规范(Button、Input、Table)|高频生成,最容易出现不一致| +|🔴 必须|状态与反馈模式|最能体现产品质感的细节| +|🟡 重要|字体系统|防止 AI 混用字号和字重| +|🟡 重要|可访问性基线|事后补救成本极高| +|🟡 重要|禁止模式|比"应该做什么"更有效| +|🟢 加分|动效规范|统一产品"手感"| +|🟢 加分|响应式断点|避免断点不一致的多设备问题| + +--- + +**核心原则**:`UI_SYSTEM.md` 不是设计文档,是给 AI 的**决策树**。当 AI 面对"这里用什么颜色?""这个按钮多大?""错误怎么展示?"时,答案必须在这里找到,不能靠猜。 \ No newline at end of file diff --git a/Project/fonrey/UI&UX/组件清单.md b/Project/fonrey/UI&UX/组件清单.md new file mode 100644 index 00000000..3d42dfd0 --- /dev/null +++ b/Project/fonrey/UI&UX/组件清单.md @@ -0,0 +1,1265 @@ +## 技术选型 + +- Frontend: HTMX + Alpine.js + Tailwind CSS +- Backend: Django 4.x (ASGI mode) +- Multi-tenant: django-tenants (Postgres schema isolation) +- Database: PostgreSQL + PgBouncer +- Cache: Redis +- Tasks: Celery + Celery Beat +- Storage: Cloudflare R2 (or AWS S3) +- CDN: Cloudflare +- Server: Gunicorn + Uvicorn workers + Nginx +- Monitoring: Sentry + Grafana + +## Data Table (数据表格) + +![[Data Table.png]] + +#### 1. Data Table(数据表格)— 核心组件 + +**你描述的"数据列表"正式名称是:Sortable Data Table with Column Visibility Control** + +图中包含的子特性: + +|子特性|技术实现方式|可行性| +|---|---|---| +|多列表头,带排序箭头(↑↓)|Django 后端排序 + HTMX 请求 + Tailwind 样式|✅ 完全可行| +|行 Checkbox 多选|Alpine.js 管理选中状态|✅ 完全可行| +|行高亮(图中蓝色高亮行)|Alpine.js `:class` 绑定|✅ 完全可行| +|红色/橙色 Tag 标签(买卖、出租)|Tailwind `badge` 样式|✅ 完全可行| +|行内小图标按钮(电梯、满五等)|Tailwind + inline SVG icon|✅ 完全可行| +|价格字段带趋势小箭头(↑绿色)|Alpine.js 条件渲染|✅ 完全可行| +|列固定宽度 + 横向滚动条|Tailwind `overflow-x-auto` + `min-w`|✅ 完全可行| + +--- + +#### 2. Pagination(分页组件) + +图中右下角的 `共3629条 < 1 2 3 4 5 … 182 > 20条/页 跳至` + +|子特性|实现方式|可行性| +|---|---|---| +|页码导航|Django Paginator + HTMX `hx-get`|✅ 完全可行| +|每页条数选择(20条/页)|Alpine.js 下拉 + HTMX 请求|✅ 完全可行| +|跳至指定页|Alpine.js 输入框 + HTMX 请求|✅ 完全可行| +|省略号(…)页码|Django 后端分页逻辑生成|✅ 完全可行| + +--- + +#### 3. Column Visibility Panel(自定义列显示) + +图中右上角的 **"自定义列表"** 按钮 + +|子特性|实现方式|可行性| +|---|---|---| +|弹出面板,勾选显示/隐藏列|Alpine.js `x-show` + `x-data`|✅ 完全可行| +|列显示状态持久化|Alpine.js + `localStorage` 或后端存储|✅ 完全可行| +|动态隐藏表格列|Alpine.js `:class="{'hidden': !col.visible}"`|✅ 完全可行| + +--- + +#### 4. Toolbar(操作工具栏) + +图中顶部的 `房源海报 批量分享 批量收藏 取消收藏 设置保护房 更多▼` + +|子特性|实现方式|可行性| +|---|---|---| +|批量操作按钮(依赖 Checkbox 选中状态)|Alpine.js 全局选中状态 + 按钮 disabled 控制|✅ 完全可行| +|"更多"下拉菜单(Dropdown Menu)|Alpine.js `x-show` + `@click.away`|✅ 完全可行| +|共 N 条(动态数字)|HTMX 局部刷新 或 Alpine.js 绑定|✅ 完全可行| + +--- + +#### 5. Export Button(导出按钮) + +图中右上角 **"导出"** 按钮 + +|实现方式|可行性| +|---|---| +|Django 后端生成 CSV/Excel(用 `openpyxl`),返回文件流|✅ 完全可行,无需前端特殊处理| +|异步导出(数据量大时走 Celery 任务,邮件通知)|✅ 你的 Celery 栈已完全支持| + +--- + +#### 6. Smart Sort(智能排序) + +图中右上角 **"按智能排序"** 标签 + +| 实现方式 | 可行性 | +| ------------------------------- | ------ | +| 后端 Django ORM 多字段排序,HTMX 切换排序模式 | ✅ 完全可行 | + + +## Modal Dialog (模态对话框) +![[Modal Dialog.png]] +### 🪟 组件名称:Modal Dialog(模态对话框) + +图中这个"编辑房源价格"弹窗,包含以下子组件: + +#### 弹窗本体结构 + +|部位|组件名称|实现方式|可行性| +|---|---|---|---| +|灰色半透明遮罩层|Backdrop / Overlay|Tailwind `bg-black/50 fixed inset-0`|✅| +|白色弹窗卡片|Modal Panel|Tailwind `bg-white rounded-lg shadow-xl`|✅| +|顶部标题栏 + ✕ 关闭按钮|Modal Header|Alpine.js `@click="open=false"`|✅| +|底部确定/取消按钮组|Modal Footer / Button Group|Tailwind 按钮样式|✅| +|拖拽手柄(左上角 ⠿ 图标)|Draggable Handle|需要少量原生 JS 或 Alpine.js 插件|⚠️| + +#### 弹窗内的表单组件 + +|组件|名称|实现方式|可行性| +|---|---|---|---| +|带星号必填标记的标签|Required Field Label|Tailwind `text-red-500` + `*` 字符|✅| +|数字输入框 + 单位后缀(万)|Input with Suffix Addon|Tailwind Input Group|✅| +|普通文本输入框(售价/备案价)|Text Input|Tailwind `input` 样式|✅| +|多行文本域(更改理由)|Textarea|Tailwind `textarea` + 字数统计 `0/200`|✅| +|字数计数(右下角 0/200)|Character Counter|Alpine.js `x-model` + `:text="val.length + '/200'"`|✅| + +--- + +### ⚠️ 唯一需要注意的点:弹窗拖拽 + +图中左上角有一个 **⠿ 拖拽图标**,说明这个弹窗支持**拖动位置**。这个功能: + +- Alpine.js 原生**不内置**拖拽 +- 可以用 **Alpine.js 官方插件 `@alpinejs/drag`** 解决,无需引入额外大型库 + +### ✅ 结论 + +> 这个 Modal 弹窗及其内部所有表单组件,**用 Alpine.js + Tailwind CSS 完全可以实现**,包括开关状态、表单验证、字数统计。拖拽功能用 Alpine 官方插件即可覆盖,无需引入 Vue/React。 + +## Tree Select/Cascading Dropdown(树形下拉选择器) + +### 🌲 组件名称:Tree Select / Cascading Dropdown(树形下拉选择器) +![[Tree Select.png]] +#### 结构拆解 + +|部位|组件名称|说明| +|---|---|---| +|触发框(点击展开)|Select Trigger Input|显示已选内容,点击展开下拉| +|下拉面板|Dropdown Panel|绝对定位浮层,`z-index` 覆盖页面| +|可折叠父节点(▶ 沪居地产)|Tree Node / Collapsible Group|点击 ▶ 展开/收起子节点| +|子节点列表(上海豪园店等)|Tree Leaf Node|可点击选中| +|带头像的叶节点(沪居地产共享)|Tree Leaf with Avatar|头像 + 姓名 + 编号 + 操作链接| +|带状态标签的节点(沪居 关闭)|Node with Badge|橙色"关闭"tag| +|底部操作行(隐藏离职员工)|Footer Action|固定在下拉底部的全局操作| + +--- + +### 技术实现评估 + +#### ✅ 可行部分(Alpine.js 处理) + +``` +树形数据展开/折叠 → Alpine.js x-data 维护每个节点的 open 状态 +选中节点高亮 → Alpine.js :class 绑定 +点击外部关闭 → Alpine.js @click.away +头像/Badge/标签 → 纯 Tailwind CSS +底部固定操作行 → Tailwind sticky bottom +``` + +#### ⚠️ 需要重点关注的点 + +**这是你上传的三张图里技术难度最高的组件**,原因: + +1. **树形数据递归渲染**:HTMX 本身不擅长递归组件,需要 Alpine.js 配合后端返回的 JSON 数据,在前端用 `template` + `x-for` 递归渲染树节点 +2. **多级嵌套状态管理**:每个父节点独立维护 `open/close` 状态,需要 Alpine.js `x-data` 设计合理的数据结构 +3. **搜索过滤**(如果需要在下拉内搜索员工):需要 Alpine.js 实时过滤树节点,或 HTMX 请求后端过滤 + +--- + +### 💡 实现建议 + +**方案一(推荐):Alpine.js 纯前端渲染** + +> 后端一次性返回完整树形 JSON,Alpine.js 前端递归渲染,适合数据量不大的组织架构树 + +**方案二:HTMX 懒加载节点** + +> 点击展开节点时,HTMX `hx-get` 请求该节点的子数据,适合层级很深、数据量很大的场景 + +--- + +### ✅ 结论 + +> 可以实现,但这是你目前三个组件里**唯一需要认真设计前端数据结构**的组件,不能直接套 Flowbite 现成组件(Flowbite 没有 TreeSelect)。建议直接基于 Alpine.js 手写,逻辑量约 80~120 行 JS,可复用。 + + +## 带搜索的 Tree Select 完整功能清单 +![[Tree Select Search 2.png]] +### 🔍 带搜索的 Tree Select 完整功能清单 + +#### 新增的搜索相关特性 + +| 特性 | 说明 | 实现方式 | 可行性 | +| ------------ | -------------- | --------------------------- | --- | +| 下拉顶部搜索输入框 | 打开下拉后可直接键入关键词 | Alpine.js `x-model="query"` | ✅ | +| 实时过滤节点 | 输入时同步过滤匹配的节点 | Alpine.js computed 过滤 | ⚠️ | +| 搜索命中时自动展开父节点 | 子节点匹配时其父节点强制展开 | 需要递归遍历树形数据 | ⚠️ | +| 无结果时显示空状态 | "暂无匹配结果" | Alpine.js `x-show` | ✅ | +| 清空搜索恢复原始树结构 | 删除关键词后还原展开状态 | Alpine.js 状态重置 | ✅ | + +## Data Range Picker (日期范围选择) + +![[Date Range Picker.png]] +这个组件的正式名称是 **Date Range Picker(日期范围选择器)**,也叫 **Dual-Month Calendar Picker**。 + +--- + +### 📅 组件名称:Date Range Picker / 双月日历范围选择器 + +#### 结构拆解 + +|部位|说明| +|---|---| +|顶部输入框组(开始日期 → 结束日期)|Range Input Group,两个输入框用箭头连接,点击任意一个触发日历展开| +|双月并排日历面板|Dual Calendar Panel,左侧当月、右侧次月,联动翻页| +|月份导航(« < 2026年4月 > »)|单箭头切换月,双箭头切换年| +|今日高亮(23日红框)|当天日期特殊样式| +|选中日期高亮(26日蓝底)|已选日期样式| +|范围区间高亮(开始~结束之间蓝色背景)|Range Highlight,区间内日期浅蓝背景| +|跨月灰色日期(上下月溢出日)|灰色不可选日期| + +--- + +### 技术实现评估 + +#### ⚠️ 这是目前为止难度最高的组件 + +**难点在于:** + +1. **双月联动**:左右两个月份需要同步,翻页时右月始终等于左月+1 +2. **区间拖选高亮**:鼠标 hover 时实时预览区间,需要精细的状态管理 +3. **日期计算**:需要处理月份天数、周几起始、跨年等边界情况 + +--- + +### 💡 强烈推荐:直接用成熟库,不要手写 + +用 Alpine.js 从零手写一个双月 Date Range Picker 工作量巨大(400~600 行),且边界情况多,极易出 Bug。 + +#### 推荐方案:**Pikaday** 或 **Flatpickr** + +|库|特点|与你技术栈的兼容性| +|---|---|---| +|**Flatpickr**(强烈推荐)|轻量、无依赖、原生支持 Range 模式和双月显示,样式可用 Tailwind 覆盖|✅ 完美兼容,CDN 引入即用| +|**Pikaday**|更轻量,但双月需手动配置|✅ 可用,略需配置| + +**Flatpickr 双月 Range 模式只需三行配置:** + +javascript + +```javascript +flatpickr("#dateRange", { + mode: "range", + showMonths: 2, +}); +``` + +> 样式用 Tailwind 自定义覆盖即可达到图中效果,不破坏你"不混用技术"的原则——Flatpickr 是无框架依赖的纯 JS 工具库,不是 React/Vue 组件。 + +--- + +### ✅ 结论 + +> **不建议用 Alpine.js 手写**,引入 **Flatpickr**(CDN,约 16KB)是最优解,与你的 HTMX + Alpine.js + Tailwind 技术栈**完全兼容、无冲突**,实现图中效果只需少量配置。 + + +## Tab Navigation (标签页导航) + +### 🗂️ 组件名称:Tabs / Tab Navigation(标签页导航) + +#### 结构拆解 + +|部位|说明| +|---|---| +|Tab 标签栏|横向排列的标签按钮组,当前激活项(修改跟进)有橙色下划线 + 橙色文字| +|激活指示器|Active Indicator,图中为橙色底部边框线| +|Tab 内容面板|切换标签时显示对应内容区域| +|内容区:Timeline(时间线)|按日期分组的操作记录列表,左侧橙色圆点| +|内容区:Banner 提示条|顶部"智能总结"广告/提示横条| +|内容区:Activity Item(活动记录项)|每条记录含【操作类型】+ 操作人 + 时间 + 详情文字| +|每条记录右侧:Visibility Toggle|"公开/隐藏"文字切换按钮| +|底部:Load More Button|"查看全部跟进"加载更多按钮| + +--- + +### 技术实现评估 + +#### Tab 切换本体 + +这是所有组件里**实现最简单**的之一: + +html + +```html + +
+ + +
+ +
+
+``` + +#### 各子组件评估 + +|子组件|实现方式|可行性| +|---|---|---| +|Tab 标签切换 + 激活样式|Alpine.js `x-data` + `:class`|✅ 极简单| +|切换时局部刷新内容|HTMX `hx-get` + `hx-target`|✅ 完全可行| +|Timeline 时间线布局|Tailwind `border-l` + 圆点 `rounded-full`|✅ 纯 CSS 实现| +|活动记录条目|Django 模板循环渲染|✅ 完全可行| +|公开/隐藏 Toggle|HTMX `hx-post` 局部更新|✅ 完全可行| +|查看全部(加载更多)|HTMX `hx-get` + `hx-swap="beforeend"`|✅ 完全可行,无需写 JS| + +--- + +### 💡 HTMX 在这里特别适合 + +"查看全部跟进"这个**加载更多**的场景,正是 HTMX 的强项: + +html + +```html + +``` + +点击后自动追加新内容到列表末尾,**零 JS**。 + +--- + +### ✅ 结论 + +> 这张图里的所有组件都是你技术栈的**舒适区**,Tab 切换 + Timeline + 加载更多,正是 HTMX + Alpine.js + Tailwind 组合最擅长的经典场景,实现难度低,代码量少。 + + +## Collapsible Card Grid(折叠展开面板) +![[Collapsible Card Grid.png]] + +### 🪗 组件名称:Collapsible Card Grid(可折叠卡片网格) + +#### 结构拆解 + +|部位|说明| +|---|---| +|外层容器|Card / Panel,带边框圆角的白色区块| +|标题栏(相关员工 + 编辑)|Section Header,右侧"编辑"为文字链接按钮| +|内容网格|3列 Grid Layout,每格一个员工卡片| +|员工卡片|Avatar + 姓名 + 门店 + 电话 + 更多按钮(橙色 ···) + 角色标签 + 日期| +|空状态格子(暂无 暂未分配)|Empty State Cell,灰色占位| +|底部展开/收起按钮|Expand Toggle Button,带 ∨ 箭头图标| + +--- + +### 技术实现评估 + +#### 折叠展开本体 — 极其简单 + +html + +```html +
+ + +
+ +
+ + + + +
+``` + +#### 各子组件评估 + +|子组件|实现方式|可行性| +|---|---|---| +|展开/收起动画|Tailwind `transition-all duration-300` + Alpine.js|✅ 极简单| +|3列网格布局|Tailwind `grid grid-cols-3 gap-4`|✅ 纯 CSS| +|员工头像|Tailwind `rounded-full` + ``|✅ 纯 CSS| +|橙色 ··· 更多按钮|Alpine.js Dropdown `@click.away`|✅ 简单| +|角色标签(出售方/钥匙方…)|Tailwind `text-blue-500` 文字链接样式|✅ 纯 CSS| +|空状态格子|Django 模板条件渲染 `{% if %}`|✅ 后端处理| +|箭头旋转动画(∨ → ∧)|Tailwind `rotate-180 transition`|✅ 一个 class 搞定| + +--- + +### ✅ 结论 + +> 这是你上传的所有截图里**实现最简单的组件**,Alpine.js 核心逻辑只需 2 行,配合 Tailwind 的 `transition` + `max-h` 控制即可实现带动画的折叠展开效果,完全不需要任何额外库。 + + +## Photo Gallery Manager (相册管理器) +![[Photo Gallery Manager 1.png]] +![[Photo Gallery Manager 2.png]] +这两张图合在一起是一个完整的 **Photo Gallery Manager(相册管理器)**,是你上传的所有截图里**功能最复合、复杂度最高**的页面。下面逐一拆解: + +--- + +### 🖼️ 组件清单 & 可行性分析 + +#### 1. Scrollable Tab Bar(可横向滚动的标签栏) + +图一顶部的分类标签,超出宽度后有 `···` 溢出菜单 + +|特性|实现方式|可行性| +|---|---|---| +|横向滚动标签|Tailwind `overflow-x-auto flex`|✅| +|溢出 `···` 下拉菜单|Alpine.js Dropdown|✅| +|激活状态(橙色下划线)|Alpine.js `:class` 绑定|✅| +|切换后刷新图片网格|HTMX `hx-get` + `hx-target`|✅| + +--- + +#### 2. Image Grid with Checkbox(可多选的图片网格) + +|特性|实现方式|可行性| +|---|---|---| +|多列图片网格|Tailwind `grid grid-cols-6 gap-2`|✅| +|每张图左上角 Checkbox|Alpine.js 管理选中状态数组|✅| +|封面角标(红色"封面"标签)|Tailwind 绝对定位 `absolute top-0 right-0`|✅| +|图片底部信息条(类别+尺寸)|Tailwind `absolute bottom-0` 半透明黑条|✅| +|全选 Checkbox|Alpine.js `selectAll` 方法|✅| + +--- + +#### 3. Batch Action Toolbar(批量操作工具栏) + +`批量修改类别 ∨` `批量删除` `批量下载` + +|特性|实现方式|可行性| +|---|---|---| +|按钮依赖选中状态启用/禁用|Alpine.js `:disabled="selected.length === 0"`|✅| +|批量删除|HTMX `hx-delete` 发送选中 ID 列表|✅| +|批量下载|Django 后端打包 zip,返回文件流(Celery 异步)|✅| +|批量修改类别下拉|Alpine.js Dropdown + HTMX `hx-post`|✅| + +--- + +#### 4. Drag-and-Drop File Upload(拖拽上传)⚠️ + +图二弹窗中的 `+ 上传图片` 区域 + +|特性|实现方式|可行性| +|---|---|---| +|点击选择文件|原生 ``|✅| +|拖拽上传区域|Alpine.js 监听 `dragover` / `drop` 事件|✅| +|上传预览(传后显示缩略图)|Alpine.js `FileReader` API|✅| +|上传进度|`XMLHttpRequest` / `fetch` + Alpine.js 进度绑定|✅| +|上传到 Cloudflare R2|Django 后端接收后转存 R2(boto3)|✅| + +> ⚠️ **建议引入 [Filepond](https://pqina.nl/filepond/)(轻量无框架依赖)**:拖拽、预览、进度、多文件队列全部内置,与你的技术栈完全兼容,避免手写大量事件处理代码。 + +--- + +#### 5. Drag-to-Reorder(拖拽调整图片顺序)⚠️ 最高难度 + +图一右上角"调整图片顺序"功能 + +|特性|实现方式|可行性| +|---|---|---| +|图片网格内拖拽排序|需要专门的拖拽排序库|⚠️| +|排序后保存到后端|HTMX `hx-post` 发送新顺序 ID 数组|✅| + +> ⚠️ **建议引入 [SortableJS](https://sortablejs.github.io/Sortable/)(3KB,无框架依赖)**:专为网格/列表拖拽排序设计,有官方 Alpine.js 集成方案,与你的技术栈完美兼容。 + +--- + +#### 6. Upload Modal 内的批量分类(图二) + +|特性|实现方式|可行性| +|---|---|---| +|上传后在弹窗内全选/选择|Alpine.js 管理已上传文件的选中状态|✅| +|批量设置分类下拉|Alpine.js Select + HTMX 提交|✅| + +--- + +### 📦 最终引入库汇总建议 + +|库|用途|大小|是否破坏技术栈一致性| +|---|---|---|---| +|**Filepond**|拖拽上传 + 预览 + 进度|~50KB|❌ 无框架依赖,安全引入| +|**SortableJS**|图片拖拽排序|~3KB|❌ 无框架依赖,安全引入| + +--- + +### ✅ 总结 + +> 这个相册管理器的**90%功能**可以用 HTMX + Alpine.js + Tailwind 原生实现。仅**拖拽上传**和**拖拽排序**这两个功能,强烈建议引入 Filepond 和 SortableJS,两者都是无框架依赖的纯 JS 工具库,不破坏你技术栈的一致性,且都有成熟的 Alpine.js 集成方案。 + + +## Image Lightbox View (全屏图片灯箱预览器) +![[Image Lightbox View.jpg]] +### 🔍 组件名称:Image Lightbox Viewer(全屏图片灯箱预览器) + +上一个是**管理后台的相册管理器**(用于上传/删除/分类),这个是**面向用户的全屏预览器**,两者职责完全不同。 + +#### 结构拆解 + +|部位|组件名称|可行性| +|---|---|---| +|全屏黑色遮罩背景|Fullscreen Overlay|✅ Tailwind `fixed inset-0 bg-gray-800`| +|左上角图片信息栏(上传人/时间/尺寸/来源)|Image Meta Header|✅ Django 模板渲染| +|右上角 ✕ 关闭按钮|Close Button|✅ Alpine.js `@click="open=false"`| +|左右切换箭头(`<` `>`)|Prev/Next Arrow Navigation|✅ Alpine.js 索引切换| +|中央主图显示区|Main Image Viewer|✅| +|底部工具栏(刷新/缩小/100%/放大/旋转/下载)|Image Toolbar|⚠️ 见下方说明| +|底部分类标签栏(全部/户型图/客厅/卧室…)|Category Filter Tab|✅ Alpine.js 过滤| +|底部缩略图条(Thumbnail Strip)|Thumbnail Filmstrip|✅ Tailwind 横向滚动| +|当前激活缩略图高亮(橙色边框)|Active Thumbnail|✅ Alpine.js `:class`| + +--- + +### ⚠️ 底部工具栏的特殊说明 + +图中工具栏包含:**缩放(放大/缩小/100%)+ 旋转 + 下载**,这是难点: + +|功能|建议方案|可行性| +|---|---|---| +|图片缩放 + 拖拽平移|引入 **[Viewer.js](https://fengyuanchen.github.io/viewerjs/)**(5KB,无依赖)|✅ 强烈推荐| +|图片旋转|Viewer.js 内置|✅| +|下载|原生 `` 或 Django 返回文件流|✅| + +--- + +### 💡 最佳实现方案 + +> 直接引入 **Viewer.js**,它能覆盖这张图里**所有**预览交互(缩放/旋转/全屏/翻页/缩略图条),配合 Alpine.js 控制开关,Tailwind 覆盖样式,**完全不破坏技术栈一致性**。 + +--- + +### 📦 更新引入库汇总 + +|库|用途|大小| +|---|---|---| +|Filepond|拖拽上传|~50KB| +|SortableJS|图片拖拽排序|~3KB| +|**Viewer.js**|图片灯箱预览(新增)|~5KB| +|Flatpickr|日期范围选择|~16KB| + +这四个库全部无框架依赖,与你的技术栈完全兼容。继续上传! + +## Accordion Progress Panel(可折叠进度检查面板) +![[Accordion Progress Panel.png]] + +### 📊 组件名称:Accordion Progress Panel(可折叠进度检查面板) + +#### 整体结构拆解 + +|部位|组件名称|可行性| +|---|---|---| +|顶部标题 + 总进度百分比(69%)|Section Header with Score|✅| +|顶部橙色进度条|Progress Bar|✅ Tailwind `w-[69%] bg-orange-500`| +|说明文字 + 蓝色文字链接|Description with Text Link|✅| +|可折叠父行(重点信息 ∧)|Accordion Header Row|✅ Alpine.js| +|折叠后的子条目列表|Accordion Body|✅ Alpine.js `x-show`| +|不可折叠的普通行(实勘/VR…)|Static Row|✅ 纯 HTML| +|每行右侧分数(4% / 8%)|Score Display|✅| +|未达标分数红色高亮(0%)|Conditional Color|✅ Alpine.js / Django 模板条件| +|行内蓝色操作链接(去上传/新增委托)|Inline Action Link|✅| + +--- + +### 技术实现评估 + +#### 折叠逻辑 — 与上一个 Collapsible 完全一致,极简单 + +html + +```html +
+ +
+ 重点信息 + + + 8% / 8% +
+ + +
+
+ 唯一住房 + 1% / 1% +
+ +
+
+``` + +#### 各细节评估 + +|细节|实现方式|可行性| +|---|---|---| +|箭头 ∧/∨ 旋转动画|Tailwind `:class="open ? 'rotate-0' : 'rotate-180'"`|✅| +|折叠动画(高度过渡)|Alpine.js 官方插件 **`x-collapse`**(官方出品,1KB)|✅| +|已得分红色/黑色条件样式|Django 模板 `{% if score == 0 %}text-red-500{% endif %}`|✅| +|多个独立折叠块互不影响|每个父行独立 `x-data="{ open: true }"`|✅| +|进度条宽度动态绑定|Django 后端计算百分比,模板输出 `style="width:69%"`|✅| + +--- + +### 💡 一个小提示 + +图中箭头标注了 4 处可折叠行(重点信息、附件、营销、带看),其余行(实勘/VR/钥匙等)是**不可折叠的普通行**。建议后端返回数据时带一个 `is_collapsible` 字段,Django 模板根据此字段决定渲染折叠版还是普通版,逻辑清晰且易维护。 + +--- + +### ✅ 结论 + +> 这个组件完全在 Alpine.js + Tailwind 的舒适区内,加上官方 `x-collapse` 插件处理高度动画,实现难度**很低**,与之前分析的 Collapsible Section 是同一类组件,可以复用同一套折叠逻辑。 + +## Inline Edit Mode (页面级读写切换) + + +### ✏️ 组件名称:Inline Edit Mode / 页面级读写切换 +![[Inline Edit Mode.png]] +#### 整体页面结构拆解 + +|部位|组件名称|可行性| +|---|---|---| +|顶部面包屑导航(系统/设置/…)|Breadcrumb|✅ 纯 Tailwind| +|顶部搜索框(输入设置项名称)|Settings Search Input|✅ Alpine.js 实时过滤| +|左侧多级导航菜单|Sidebar Navigation with Accordion|✅ Alpine.js(与之前折叠组件同理)| +|右上角"编辑"按钮|Edit Toggle Button|✅ Alpine.js| +|内容区分组标题(员工信息设置…)|Section Divider with Title|✅ 纯 Tailwind| +|左侧橙色竖线分组标签(个人信息)|Labeled Group Divider|✅ Tailwind `border-l-4 border-orange-500`| +|Toggle 开关(橙色/灰色)|Toggle Switch|✅ Alpine.js + Tailwind| +|只读文字 → 编辑后变输入框|Read/Edit Mode Switch|✅ Alpine.js `x-show`| + +--- + +### 核心交互:Read/Edit Mode Toggle + +这是本页最关键的设计模式,实现思路非常清晰: + +html + +```html +
+ + + + + + +
+ 工龄计算方式 + + + 从首次入职开始计算 + + + +
+ + + + +
+``` + +--- + +### 各组件详细评估 + +|组件|只读态|编辑态|可行性| +|---|---|---|---| +|文字类设置(工龄计算方式)|纯文本 ``|``|✅ Alpine.js `x-show` 切换| +|Toggle 开关|显示当前状态,`disabled`|可操作|✅ `:disabled="!editing"`| +|保存操作|—|HTMX `hx-post` 提交表单|✅ 无需页面跳转| +|取消编辑|—|恢复原始值|✅ Alpine.js 保存快照 `JSON.parse(JSON.stringify(data))`| + +--- + +### Toggle Switch 组件 + +图中橙色开关是高频组件,纯 Tailwind + Alpine.js 实现: + +html + +```html + +``` + +--- + +### 左侧 Sidebar 导航 + +图中左侧菜单含**二级展开**(人事OA设置 ∧ 展开子项),与之前分析的折叠组件完全相同的实现方式,可直接复用。 + +--- + +### ✅ 结论 + +> 这整个页面的所有交互,包括**读写模式切换、Toggle 开关、左侧折叠导航、保存提交**,全部在 Alpine.js + HTMX + Tailwind 的能力范围内,**无需引入任何新库**。 + +> 唯一需要注意的是**取消编辑时恢复原始值**,建议进入编辑态时用 Alpine.js 做一次数据快照,取消时还原,这是标准做法,约 3 行代码。 + + +## Drawer / Slide-over Panel(右侧抽屉面板) +![[Drawer Slide over.png]] +### 🗂️ 组件名称:Drawer / Slide-over Panel(右侧抽屉面板) + +#### 整体页面结构拆解 + +|部位|组件名称|可行性| +|---|---|---| +|左侧主内容区(数据表格)|Data Table(与第一张图同类)|✅| +|右侧从屏幕边缘滑入的面板|Drawer / Slide-over|✅ Alpine.js + Tailwind| +|右侧面板顶部标题栏|Drawer Header|✅| +|右侧面板底部确定/取消按钮|Drawer Footer(固定在底部)|✅ Tailwind `sticky bottom-0`| +|半透明遮罩(左侧内容变暗)|Backdrop Overlay|✅| +|右侧面板内的表格|Settings Table with Radio + Toggle|✅| + +--- + +### 核心交互:Drawer 滑入滑出 + +html + +```html +
+ + + + + +
+
+ + +
+ + +
+ 住宅/商住/别墅——出售字段填写要求和新增页展示设置 + +
+ + +
+ +
+ + +
+ + +
+ +
+
+``` + +--- + +### 右侧面板内的设置表格拆解 + +|列|组件|可行性| +|---|---|---| +|录入字段(文字列)|普通文本|✅| +|填写要求(必填/选填 Radio)|Radio Button Group|✅ Alpine.js `x-model`| +|录入页显示(Toggle 开关)|Toggle Switch(与上张图同款)|✅ 复用之前的 Toggle 组件| +|整列表格可滚动|Drawer 内容区 `overflow-y-auto`|✅| + +--- + +### Drawer vs Modal 的选择原则 + +图中选择用 Drawer 而非 Modal,是因为: + +|场景|推荐组件| +|---|---| +|编辑内容**字段多、需要滚动**|✅ Drawer(右侧抽屉)| +|编辑内容**字段少、简单确认**|Modal(居中弹窗,如第二张图)| +|需要**同时参考主页面内容**|✅ Drawer(主页面仍可见)| + +--- + +### ✅ 结论 + +> Drawer 是 Alpine.js + Tailwind 的经典实现场景,核心是 `x-show` + `x-transition` 的 `translate-x-full → translate-x-0` 动画,**无需引入任何新库**,与之前所有组件复用同一套 Alpine.js 状态管理模式。 + +> 这也是你系统里**Modal 和 Drawer 两种编辑入口并存**的合理设计——字段少用 Modal,字段多用 Drawer,体验上各司其职。 + + +## Multi-select Tag Input(多选标签选择器) +![[Multi-select with Tag Input.png]] +### 🏷️ 组件名称:Multi-select Tag Input(多选标签选择器) + +#### 结构拆解 + +|部位|组件名称|可行性| +|---|---|---| +|外层输入框容器(橙色边框激活态)|Tag Input Container|✅ Tailwind `ring-2 ring-orange-400`| +|已选项显示为 Tag/Chip(出售 ×)|Tag / Chip|✅ Alpine.js `x-for` 循环渲染| +|Tag 右侧 × 删除按钮|Tag Remove Button|✅ Alpine.js `@click` 移除数组元素| +|末尾光标输入框(可继续输入搜索)|Inline Search Input|✅ Alpine.js `x-model="query"`| +|下拉选项列表|Dropdown Option List|✅ Alpine.js `x-show`| +|已选项显示橙色 ✓ 勾选状态|Selected Indicator|✅ Alpine.js 判断是否在已选数组中| +|点击已选项再次点击取消选中|Toggle Selection|✅ Alpine.js 数组 push/splice| + +--- + +### 核心实现逻辑 + +javascript + +```javascript +// Alpine.js 数据结构 +{ + selected: ['出售', '出租', '租售', '他售/不售', '他租/不租', '暂缓'], + options: ['出售', '出租', '租售', '他售/不售', '他租/不租', '暂缓'], + open: false, + + toggle(option) { + const i = this.selected.indexOf(option) + i === -1 ? this.selected.push(option) : this.selected.splice(i, 1) + }, + + isSelected(option) { + return this.selected.includes(option) + }, + + remove(option) { + this.selected = this.selected.filter(s => s !== option) + } +} +``` + +html + +```html + +
+ + + + + + +
+ + +
+ +
+``` + +--- + +### 与之前组件的关系 + +|组件|选择结果呈现方式|适用场景| +|---|---|---| +|Tree Select|下拉关闭后输入框显示文字|单选,层级数据(员工/门店)| +|**Multi-select Tag Input**|每个选中项显示为可删除 Tag|**多选,平级数据(状态/标签)**| +|Date Range Picker|显示为日期区间文字|日期范围选择| + +--- + +### ✅ 结论 + +> 这是一个**中等难度**组件,Alpine.js 完全胜任,核心是维护一个**已选项数组**,Tag 的增删、下拉勾选状态、× 删除按钮全部围绕这个数组操作,逻辑清晰,约 30~50 行 JS,**无需引入任何新库**。 + + +## Dynamic Form Table(动态可增删行表格) +![[Dynamic Form Table.png]] +### ➕ 组件名称:Dynamic Form Table(动态可增删行表格) + +#### 结构拆解 + +|部位|组件名称|可行性| +|---|---|---| +|表格主体(字段名称/类型/可选内容/必填/操作)|Editable Table|✅| +|每行"是否必填"列的 Toggle+Label 组合|Toggle with Status Label|✅ Alpine.js| +|必填橙色底(必填●)/ 灰色(非必填●)|Conditional Badge + Toggle|✅ `:class` 绑定| +|操作列"隐藏不使用"文字按钮|Text Action Button|✅| +|操作列"-"(系统预置行不可删除)|Disabled State|✅ `:disabled`| +|底部"+ 添加"按钮|Add Row Button|✅ Alpine.js| + +--- + +### 核心交互:动态增删行 + +javascript + +```javascript +// Alpine.js 数据结构 +{ + rows: [ + // 系统预置行(不可删除) + { id: 1, name: '意向日期', type: '日期选择', options: '-', required: true, system: true }, + { id: 2, name: '意向价格', type: '金额输入', options: '单位-元', required: true, system: true }, + // 用户自定义行(可删除/隐藏) + { id: 3, name: '意向截止日', type: '日期选择', options: '-', required: false, system: false, hidden: false }, + ], + + addRow() { + this.rows.push({ + id: Date.now(), + name: '', type: '', options: '-', + required: false, system: false, hidden: false + }) + }, + + removeRow(id) { + this.rows = this.rows.filter(r => r.id !== id) + }, + + toggleHidden(row) { + row.hidden = !row.hidden + } +} +``` + +--- + +### 关键业务逻辑拆解 + +#### 系统预置行 vs 用户自定义行的差异 + +|行为|系统预置行|用户自定义行| +|---|---|---| +|字段名称|不可编辑(纯文本)|可编辑(``)| +|删除|操作列显示"-",不可删|可删除(显示删除按钮)| +|隐藏不使用|无此操作(前两行)|有"隐藏不使用"按钮| +|必填 Toggle|禁用不可改(系统锁定)|可自由切换| + +html + +```html + + + +``` + +#### 必填 Toggle + Badge 联动 + +html + +```html +
+ + + + + +
+``` + +#### 保存到后端 + +html + +```html + + +``` + +--- + +### ✅ 结论 + +> 这个组件完全在 Alpine.js + Tailwind + HTMX 的能力范围内,**无需引入任何新库**。核心是 Alpine.js 维护一个 `rows` 数组,增删行操作数组即可,DOM 自动响应更新。 + +> 唯一需要注意的是**系统预置行和用户自定义行的权限差异**,建议后端返回数据时携带 `is_system` 字段,前端据此控制哪些列可编辑、哪些操作可用,逻辑清晰且安全。 + + +## Sortable Table with Drag Handle(带拖拽手柄的可排序表格) +![[Sortable Table with Drage Handle.png]] +### ↕️ 组件名称:Sortable Table with Drag Handle(带拖拽手柄的可排序表格) + +#### 新增特性拆解 + +|部位|组件名称|说明| +|---|---|---| +|每行左侧 ⠿ 图标|Drag Handle|鼠标按住此处才能拖动,非整行拖动| +|拖动中的行样式|Dragging State|图中"业主"行被拖起,蓝色高亮背景| +|拖动目标位置指示|Drop Indicator|图中橙色虚线,显示将要放置的位置| +|拖动后顺序持久化|Order Persistence|拖完后保存新顺序到后端| + +--- + +### 实现方案 + +这个功能之前分析相册排序时已经推荐过 **SortableJS**,在表格场景同样适用: + +html + +```html + + + + + + +``` + +javascript + +```javascript +// Alpine.js 初始化 SortableJS +initSort() { + Sortable.create(document.getElementById('sortable-table'), { + handle: '.drag-handle', // 只有手柄可拖 + animation: 150, // 拖动动画时长 + ghostClass: 'bg-blue-50', // 拖动中行的样式(图中蓝色) + chosenClass: 'opacity-50', + + onEnd: (evt) => { + // 拖完后同步 Alpine.js 数据顺序 + const moved = this.rows.splice(evt.oldIndex, 1)[0] + this.rows.splice(evt.newIndex, 0, moved) + + // 保存新顺序到后端 + this.saveOrder() + } + }) +}, + +saveOrder() { + const ids = this.rows.map(r => r.id) + // HTMX 或 fetch 提交新顺序 + fetch('/api/field-options/reorder/', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ ids }) + }) +} +``` + +--- + +### Drop Indicator(橙色虚线放置指示线) + +图中橙色虚线是视觉上最精细的部分,SortableJS 的 `ghostClass` 可以控制占位样式: + +css + +```css +/* 拖动占位行显示橙色虚线边框 */ +.sortable-ghost { + border: 2px dashed #f97316; /* Tailwind orange-500 */ + background: transparent; + opacity: 0.4; +} +``` + +--- + +### 与上一张图的差异对比 + +|特性|上张(动态表格)|本张(可拖拽排序)| +|---|---|---| +|新增行|✅ + 添加|✅ + 新增| +|删除行|✅|✅| +|Toggle 开关|✅|✅| +|**行拖拽排序**|❌|✅ SortableJS| +|**拖拽手柄 ⠿**|❌|✅| +|**Drop 虚线指示**|❌|✅ CSS ghostClass| + +--- + +### ✅ 结论 + +> SortableJS 在这个场景和之前相册排序场景是**同一个库**,引入一次即可在整个系统复用。与 Alpine.js 的集成非常自然,拖拽完成后通过 `onEnd` 回调同步 Alpine.js 数据状态,再用 `fetch` 或 HTMX 提交新顺序,**整体方案无缝衔接你的技术栈**。 + + +## Multi-Table Independent Pagination(同页多表格独立分页) +![[Multi-Table Independent Pagination.png]] +### 📋 组件名称:Multi-Table Independent Pagination(同页多表格独立分页) + +#### 页面结构拆解 + +|部位|组件名称|可行性| +|---|---|---| +|顶部搜索栏 + 橙色搜索按钮 + 重置|Search Bar|✅| +|顶部 Tab 导航(交易信息/房产信息…)|Tab Navigation(与之前同款)|✅| +|右上角"已移除参数 / 新增参数"按钮组|Action Button Group|✅| +|多个独立表格分区(业客信息/合同应收费用…)|Section Table|✅| +|每个表格右下角**独立分页器**|Per-Table Pagination|✅ HTMX 精准局部刷新| +|分区标题 + 说明文字|Section Header with Description|✅| + +--- + +### 核心难点:同页多表格独立分页 + +这正是 **HTMX 最擅长的场景**,每个表格是独立的 `hx-target`,互不干扰: + +html + +```html + +
+

业客信息

+ + +
+ {% include "partials/table_customer.html" %} +
+ + +
+ + 1 + + + +
+
+ + +
+

合同-应收费用

+ +
+ {% include "partials/table_fee.html" %} +
+ + +
+ + 1 + +
+
+``` + +--- + +### 关键设计原则 + +每个表格区块的**三要素相互隔离**: + +``` +表格1 表格2 表格3 + │ │ │ + ├─ id="table-1" ├─ id="table-2" ├─ id="table-3" + ├─ hx-target 指向 ├─ hx-target 指向 ├─ hx-target 指向 + │ #table-1 │ #table-2 │ #table-3 + └─ /api/t1/?page=N └─ /api/t2/?page=N └─ /api/t3/?page=N + +翻表格1的页 → 只有 #table-1 的 DOM 更新,表格2、3完全不动 +``` + +--- + +### 顶部搜索的联动逻辑 + +顶部搜索框搜索时,需要**同时刷新所有表格**: + +html + +```html +
+ hx-swap="innerHTML"> + + + +
+ +
+ +
+``` + +--- + +### ✅ 结论 + +> 这个模式是 HTMX **`hx-target` 精准局部刷新**的最典型应用场景:每个表格的分页器只更新自己的 `target`,**天然实现多表格独立分页**,无需任何前端状态管理,**零 JS 代码**,完全由 HTML 属性声明驱动。 + +> Django 后端只需为每个表格区块提供独立的分页视图接口即可,架构清晰,维护成本极低。 \ No newline at end of file diff --git a/Project/fonrey/screenshots/页面组件/Accordion Progress Panel.png b/Project/fonrey/screenshots/页面组件/Accordion Progress Panel.png new file mode 100644 index 00000000..2896b3f5 Binary files /dev/null and b/Project/fonrey/screenshots/页面组件/Accordion Progress Panel.png differ diff --git a/Project/fonrey/screenshots/页面组件/Collapsible Card Grid.png b/Project/fonrey/screenshots/页面组件/Collapsible Card Grid.png new file mode 100644 index 00000000..0daeafd1 Binary files /dev/null and b/Project/fonrey/screenshots/页面组件/Collapsible Card Grid.png differ diff --git a/Project/fonrey/screenshots/页面组件/Data Table.png b/Project/fonrey/screenshots/页面组件/Data Table.png new file mode 100644 index 00000000..935b8eae Binary files /dev/null and b/Project/fonrey/screenshots/页面组件/Data Table.png differ diff --git a/Project/fonrey/screenshots/页面组件/Date Range Picker.png b/Project/fonrey/screenshots/页面组件/Date Range Picker.png new file mode 100644 index 00000000..4ea138e3 Binary files /dev/null and b/Project/fonrey/screenshots/页面组件/Date Range Picker.png differ diff --git a/Project/fonrey/screenshots/页面组件/Drawer Slide over.png b/Project/fonrey/screenshots/页面组件/Drawer Slide over.png new file mode 100644 index 00000000..165826d0 Binary files /dev/null and b/Project/fonrey/screenshots/页面组件/Drawer Slide over.png differ diff --git a/Project/fonrey/screenshots/页面组件/Dynamic Form Table.png b/Project/fonrey/screenshots/页面组件/Dynamic Form Table.png new file mode 100644 index 00000000..452ed2e0 Binary files /dev/null and b/Project/fonrey/screenshots/页面组件/Dynamic Form Table.png differ diff --git a/Project/fonrey/screenshots/页面组件/Image Lightbox View.jpg b/Project/fonrey/screenshots/页面组件/Image Lightbox View.jpg new file mode 100644 index 00000000..005c1314 Binary files /dev/null and b/Project/fonrey/screenshots/页面组件/Image Lightbox View.jpg differ diff --git a/Project/fonrey/screenshots/页面组件/Inline Edit Mode.png b/Project/fonrey/screenshots/页面组件/Inline Edit Mode.png new file mode 100644 index 00000000..b5ba94ee Binary files /dev/null and b/Project/fonrey/screenshots/页面组件/Inline Edit Mode.png differ diff --git a/Project/fonrey/screenshots/页面组件/Modal Dialog.png b/Project/fonrey/screenshots/页面组件/Modal Dialog.png new file mode 100644 index 00000000..01a9ba0d Binary files /dev/null and b/Project/fonrey/screenshots/页面组件/Modal Dialog.png differ diff --git a/Project/fonrey/screenshots/页面组件/Multi-Table Independent Pagination.png b/Project/fonrey/screenshots/页面组件/Multi-Table Independent Pagination.png new file mode 100644 index 00000000..10f8f3ef Binary files /dev/null and b/Project/fonrey/screenshots/页面组件/Multi-Table Independent Pagination.png differ diff --git a/Project/fonrey/screenshots/页面组件/Multi-select with Tag Input.png b/Project/fonrey/screenshots/页面组件/Multi-select with Tag Input.png new file mode 100644 index 00000000..9562f78e Binary files /dev/null and b/Project/fonrey/screenshots/页面组件/Multi-select with Tag Input.png differ diff --git a/Project/fonrey/screenshots/页面组件/Photo Gallery Manager 1.png b/Project/fonrey/screenshots/页面组件/Photo Gallery Manager 1.png new file mode 100644 index 00000000..d7f25596 Binary files /dev/null and b/Project/fonrey/screenshots/页面组件/Photo Gallery Manager 1.png differ diff --git a/Project/fonrey/screenshots/页面组件/Photo Gallery Manager 2.png b/Project/fonrey/screenshots/页面组件/Photo Gallery Manager 2.png new file mode 100644 index 00000000..9961f8ee Binary files /dev/null and b/Project/fonrey/screenshots/页面组件/Photo Gallery Manager 2.png differ diff --git a/Project/fonrey/screenshots/页面组件/Sortable Table with Drage Handle.png b/Project/fonrey/screenshots/页面组件/Sortable Table with Drage Handle.png new file mode 100644 index 00000000..89e4ed1d Binary files /dev/null and b/Project/fonrey/screenshots/页面组件/Sortable Table with Drage Handle.png differ diff --git a/Project/fonrey/screenshots/页面组件/Tab Navigation.png b/Project/fonrey/screenshots/页面组件/Tab Navigation.png new file mode 100644 index 00000000..984ba01f Binary files /dev/null and b/Project/fonrey/screenshots/页面组件/Tab Navigation.png differ diff --git a/Project/fonrey/screenshots/页面组件/Tree Select Search 2.png b/Project/fonrey/screenshots/页面组件/Tree Select Search 2.png new file mode 100644 index 00000000..afbd2c14 Binary files /dev/null and b/Project/fonrey/screenshots/页面组件/Tree Select Search 2.png differ diff --git a/Project/fonrey/screenshots/页面组件/Tree Select.png b/Project/fonrey/screenshots/页面组件/Tree Select.png new file mode 100644 index 00000000..0ad6800d Binary files /dev/null and b/Project/fonrey/screenshots/页面组件/Tree Select.png differ diff --git a/Project/fonrey/指令.md b/Project/fonrey/指令.md index 55bfe7d7..df936e86 100644 --- a/Project/fonrey/指令.md +++ b/Project/fonrey/指令.md @@ -1,10 +1,42 @@ +- 文档根目录是:`~/Workspace/nexus` +- 你是一名资深的后端架构师,请你参考读取 `raw/Agent/agency-agents/engineering/engineering-backend-architect.md` 并用该文档提及的架构师方面的技能和方法论帮设计系统 +- 我希望的技术栈如下: + - Frontend: HTMX + Alpine.js + Tailwind CSS + - Backend: Django 4.x (ASGI mode) + - Multi-tenant: django-tenants (Postgres schema isolation) + - Database: PostgreSQL + PgBouncer + - Cache: Redis + - Tasks: Celery + Celery Beat + - Storage: Cloudflare R2 (or AWS S3) + - CDN: Cloudflare + - Server: Gunicorn + Uvicorn workers + Nginx + - Monitoring: Sentry + Grafana + - 部署方式: Docker Compose + - 代码管理: Git + - 编程方式: Vibe Coding +- 在做技术选型时,我分析了页面的组件并记录在 `Project/fonrey/UI&UX/组件清单.md`里 +- 项目概览 + - **系统名称**:Fonrey 房产经纪管理系统 + - **已有 PRD 模块**:房源管理(v2.1)、客源管理(v1.4)、楼盘管理(v1.0)、系统设置(v1.0),均为 Draft 状态 + - **房源管理**:支持住宅/别墅/商铺/商住/写字楼/其他 6 种房源类型(P0 住宅,P1 别墅,商业类低优先级);核心功能含录入、跟进、图片管理、价格解读、市场报盘、附件、业主联系人;目标 89,000+ 条数据量级 + - **客源管理**:管理购房/租房意向客户(私客为核心,公客/成交客后续版本);功能含录入私客、智能配房、跟进记录、活跃度分层、转公客/转成交/转无效、联系人管理、操作日志 + - **楼盘管理**:楼盘为房源基础数据底座;功能含楼盘列表、楼盘详情(楼盘信息/楼栋管理/结构管理/照片/价格走势/周边配套)、区域管理(城区/商圈/关联关系)、学校管理;聚焦二手房 + - **系统设置**:平台"控制中心";本期聚焦首页设置与房源设置(字段标签、必填规则、自定义字段、标签管理);其余设置(客源/交易/财务/人事OA/合同/通用/移动端/安装登录)在各自模块 PRD 中说明 + - 所有模块均为 Web 端,移动端适配为 v2 规划 + - **目标用户**:一线经纪人(高频)、店长/经理(每日)、运营/行政人员(每日)、系统管理员(不定期) + - 具体项目PRD文档`Project/fonrey/PRD/*.md` +- 请根据TECH_STAK文档要求 `Project/fonrey/TECH_STACK/TECH_STACK 文档要求`帮我设计TECH_STACK文档 输出到`Project/fonrey/TECH_STACK/`目录下 + + + + ## 系统提示词 - 文档根目录是:`~/Workspace/nexus` - 你是一名资深的产品经理和产品需求分析师,现在我要你根据我提供的产品截图和信息帮我分析产品功能需求并写成需求文档 - 请你参考读取 `raw/Agent/agency-agents/product/product-manager.md` 并用该文档提及的产品经理专业知识和方法论帮我进行需求分析 - 我的项目是开发一套房产经纪管理系统(Fonrey), 主要的功能是包含房源管理,客源管理以及基本的组织管理/人员管理/权限管理等。我现在有一套成熟系统的截图,我希望你根据我提供的截图和我提供的信息来分析具体的需求并写成专业的文档。 -- 现阶段已经完成`Project/fonrey/PRD/房源管理模块PRD.md`, `Project/fonrey/PRD/客源管理模块PRD.md`和``Project/fonrey/PRD/楼盘管理模块PRD.md``,你可以参考该文档格式及目录结构并继续根据以下提供的内容撰写需求文档 +- 现阶段已经完成`Project/fonrey/PRD/房源管理模块PRD.md`, `Project/fonrey/PRD/客源管理模块PRD.md`你可以参考该文档格式及目录结构并继续根据以下提供的内容撰写需求文档 - 现在请你继续分析楼盘管理 并写入`Project/fonrey/PRD/系统设置模块PRD.md` - 我提供的截图有分不同的模块: @@ -179,4 +211,22 @@ - 客源相关方设置:`Project/fonrey/screenshots/设置/客源设置-客源相关方配置.png` - 客源行政跨部门权限:`Project/fonrey/screenshots/设置/客源设置-客源行政跨部门权限.png` - 人事OA设置 - - 组织人事基本设置:`Project/fonrey/screenshots/设置/人事OA设置-组织人事设置.png` \ No newline at end of file + - 组织人事基本设置:`Project/fonrey/screenshots/设置/人事OA设置-组织人事设置.png` + + + +## 项目概况 +请根据我的PRD 文档`Project/fonrey/PRD/*.md` 里面描述的项目功能帮我写一个项目概况用于快速介绍这个项目 + + +## 技术栈 +- Frontend: HTMX + Alpine.js + Tailwind CSS +- Backend: Django 4.x (ASGI mode) +- Multi-tenant: django-tenants (Postgres schema isolation) +- Database: PostgreSQL + PgBouncer +- Cache: Redis +- Tasks: Celery + Celery Beat +- Storage: Cloudflare R2 (or AWS S3) +- CDN: Cloudflare +- Server: Gunicorn + Uvicorn workers + Nginx +- Monitoring: Promethues + Grafana \ No newline at end of file diff --git a/Project/fonrey/核心文档体系.md b/Project/fonrey/核心文档体系.md new file mode 100644 index 00000000..8a1ad97c --- /dev/null +++ b/Project/fonrey/核心文档体系.md @@ -0,0 +1,77 @@ +### 1. 产品愿景与 MVP 范围书 (`PRD_MVP.md`) + +AI 需要知道“终点”在哪里,以及“当前阶段”的界限。 + +- **核心功能清单:** 明确第一阶段(MVP)必须实现的 3-5 个核心功能。 + +- **非目标 (Out of Scope):** 明确哪些功能在 MVP 阶段**绝对不做**,防止 Claude 在生成代码时过度设计。 + +- **用户故事:** 简单的 `As a [user], I want to [action], so that [value]`,这有助于 Claude 理解业务逻辑的优先级。 + + +### 2. 技术栈与规范定义 (`TECH_STACK.md`) + +Vibe Coding 最怕 AI 随意引入不兼容的库。 + +- **固定技术栈:** 例如 Frontend (Next.js 14, Tailwind), Backend (Supabase/PostgreSQL), Auth (Clerk)。 + +- **代码风格:** 比如“使用 Functional Components”、“优先使用 TypeScript 严格模式”、“所有的 API 调用必须遵循 RESTful 规范”。 + +- **项目结构:** 预定义文件夹结构(如 `/components`, `/hooks`, `/lib`, `/types`),让 AI 生成的代码能够准确归位。 + + +### 3. 领域模型与数据库 Schema (`DATA_MODEL.md`) + +这是项目的“骨架”。即便你使用 NoSQL,也要先定义好数据关系。 + +- **实体关系图 (ERD):** 描述 User, Project, Task 等实体的关系。 + +- **Schema 定义:** 提供 SQL DDL 或 Prisma Schema 示例。 + +- **核心业务状态机:** 如果有复杂逻辑(如订单状态、工作流状态),定义好状态转换矩阵。 + + +### 4. UI/UX 风格与组件指南 (`UI_SYSTEM.md`) + +为了让生成的页面不至于太丑或不统一: + +- **设计语言:** 明确使用哪个组件库(如 shadcn/ui, Ant Design)。 + +- **核心页面路由:** 定义 MVP 阶段的所有 URL 路径及对应的功能页面。 + +- **全局布局:** 描述 Header, Sidebar, Footer 的行为。 + + +### 5. AI 指令手册 (`.cursorrules` 或 `AI_INSTRUCTIONS.md`) + +这是 Vibe Coding 的“灵魂”,专门给 Claude 看的“说明书”。 + +- **角色设定:** “你是一个资深的 Full-stack Engineer,擅长编写可维护的、高性能的 React 代码。” + +- **禁止事项:** “禁止使用任何未在 TECH_STACK.md 中定义的第三方库。” + +- **报错处理:** “如果遇到错误,优先检查类型定义,并输出详细的 Debug Log。” + +## 针对 Vibe Coding 的特化建议 + +### 1. 采用“模块化文档”而非“长篇大论” + +不要给 Claude 一个 5000 字的文档。将文档拆分为上述的 `.md` 文件。在对话时,使用 `@` 功能(在 Cursor/OpenCode 中)按需引用。例如:“基于 `@DATA_MODEL.md` 实现 `@PRD_MVP.md` 中的用户注册流程。” + +### 2. 准备“上下文脚手架” + +在开始第一行代码前,先让 Claude 生成一个 `README.md`,概括整个项目的架构。这会成为后续对话中最重要的上下文参考。 + +### 3. 动态更新的“决策记录” (`ADR.md`) + +在 Vibe Coding 过程中,AI 可能会建议一些架构改动。一旦你接受了某个改动,**立即**记录在 `Architecture Decision Records (ADR)` 中。这样当你在后续对话中开启新 Session 时,可以把这个文档丢给它,避免它推翻之前的设计方案。 + +--- + +## 建议的执行流程 + +1. **初始化阶段:** 编写上述 5 份 Markdown 文档。 + +2. **环境对齐:** 将文档喂给 Claude,问它:“基于这些文档,你认为实现 MVP 的第一步是什么?请列出任务清单。” + +3. **循环迭代:** 按照 `任务清单 -> 生成代码 -> 测试反馈 -> 更新文档` 的循环进行。 \ No newline at end of file