iloom-flatten/README.md

1451 lines
57 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 纺织行业采购计划管理系统
一款专为纺织行业设计的全流程协作管理平台,连接采购商(布行)、纺织厂、水洗厂三方,实现从计划制定到成品交付的数字化管理。
## 核心功能
### 多角色协作
- **采购商/布行**:创建生产计划、管理坯布库存、跟踪生产进度、处理结款
- **纺织厂**:接收生产计划、管理生产流程、坯布入库、纱线库存管理
- **水洗厂**:接收水洗订单、管理水洗流程
### 计划管理
- 自动生成唯一计划编号和坯布识别码
- 纱线配比配置与用量自动计算
- 生产流程节点跟踪(确认计划 → 采纱 → 染纱 → 上机 → 坯布入库)
- 实时进度可视化支持97%完成度自动提醒
### 库存管理
- **产品信息**:按坯布码分组管理,入库记录追溯
- 产品管理:支持按名称、克重、颜色多级分组展示
- 出入库历史:查看每个产品的完整库存变动记录
- 价格历史:追踪采购价格变动
- 产品唯一性:产品码全局唯一,色号在"成品名称-克重-颜色"组合中唯一
- **原料纱仓库**:库存预警、最低库存提醒
- 实时库存数据同步,入库自动更新
### 结款管理
- 按完成米数自动计算结款金额
- 待结款汇总统计
- 一键确认结款,记录结款时间
### 分享与导入
- 加密分享链接,保护敏感信息
- 支持剪贴板自动识别导入
- 扫码或链接快速关联计划
## 技术特性
### 前端技术栈
- **React 18** + TypeScript - 类型安全的函数组件开发strict模式
- **Webpack 5** - 构建工具,开发服务器端口 3015host: 0.0.0.0
- **TailwindCSS 3** + PostCSS - 原子化CSS自定义CSS变量体系
- **Framer Motion** - 页面过渡、交互动画、性能降级
- **Lucide React** - 现代化图标库
- **Recharts** - 数据可视化图表
- **React Router v6** - HashRouter 模式25条路由配置
### 多角色主题色系统
| 角色 | 主色调 | 渐变配色 | 应用场景 |
|------|--------|---------|---------|
| 采购商 | Amber | `from-amber-400 to-orange-500` | Dashboard、Layout、通知中心 |
| 纺织厂 | Emerald | `from-emerald-400 to-teal-400` | Dashboard、Layout、通知中心 |
| 水洗厂 | Violet | `from-violet-400 to-fuchsia-400` | Dashboard、通知中心 |
| 系统/公共 | Blue | `from-blue-500 to-blue-600` | 登录页、通用组件 |
### 前端配置架构
系统采用**双层配置架构**,将所有可配置项从散落的 hardcode 集中到统一配置中心:
```
src/config/app.ts ← 配置源头(环境感知、数值型配置、主题色、存储键)
↓ 导入
src/utils/constants.ts ← 向后兼容层状态枚举、UI映射、步骤配置 + 重新导出app.ts配置
↓ 导入
各业务文件 ← 消费方Hooks、页面、组件
```
#### 配置模块清单 (`src/config/app.ts`)
| 配置模块 | 导出常量 | 说明 |
|----------|---------|------|
| 环境配置 | `APP_ENV`, `IS_DEV`, `IS_PROD` | 通过 webpack DefinePlugin 注入 `__APP_ENV__` |
| 应用信息 | `APP_CONFIG` | 名称、版本号、Demo密码、免密登录有效期 |
| 演示账号 | `DEMO_ACCOUNTS`, `SHOW_DEMO_ACCOUNTS` | 三个角色的演示账号配置 |
| 缓存配置 | `CACHE_CONFIG` | 计划数据(10s)、库存数据(5s)、Dashboard(10s) |
| 分页配置 | `PAGINATION_CONFIG` | 默认页大小(20)、入库记录上限(100)、价格历史上限(50) |
| 同步配置 | `SYNC_CONFIG` | 计划状态同步间隔(开发10s/生产5min)、Realtime重连延迟 |
| 动画配置 | `ANIMATION_CONFIG` | 标准/快速/慢速过渡、弹簧动画、页面过渡、交错延迟 |
| 进度阈值 | `PROGRESS_THRESHOLDS` | 完成(97%)、低警告(30%)、中提示(60%) |
| 角色主题色 | `ROLE_THEMES`, `getRoleTheme()` | purchaser/textile/washing/system 四套完整主题色 |
| 文件上传 | `UPLOAD_CONFIG` | 图片大小限制(5MB)、允许类型、存储桶名称 |
| 分享链接 | `SHARE_CONFIG` | 链接有效期(30min)、短码长度(8) |
| 存储键 | `STORAGE_KEYS` | 所有 localStorage key 集中管理14个键 |
#### 状态枚举常量 (`src/utils/constants.ts`)
| 枚举常量 | 值 | 对应数据库枚举 |
|----------|-----|--------------|
| `PLAN_STATUS` | PENDING/PRODUCING/COMPLETED/REJECTED | plan_status |
| `STEP_STATUS` | PENDING/ACTIVE/COMPLETED/REJECTED | step_status |
| `FACTORY_TYPE` | TEXTILE/WASHING | factory_type |
| `WAREHOUSE_TYPE` | RAW_FABRIC/FABRIC/FINISHED/YARN | warehouse_type |
| `PAYMENT_STATUS` | PENDING/COMPLETED | payment_status |
| `SHARE_LINK_STATUS` | PENDING/CLICKED/CONFIRMED/REJECTED/EXPIRED/CANCELLED | share_links.status |
| `WASHING_PLAN_STATUS` | PENDING/IN_PROGRESS/COMPLETED | washing_plans.status |
| `INVENTORY_RECORD_TYPE` | IN/OUT | yarn_stock_records.record_type |
| `OUTBOUND_TYPE` | MANUAL/AUTO | product_outbound_records.outbound_type |
#### 使用规范
1. **新增配置项**:统一添加到 `src/config/app.ts`,不要在业务文件中硬编码
2. **状态字符串**:使用 `PLAN_STATUS.PENDING` 代替 `'pending'`,避免拼写错误
3. **localStorage**:使用 `STORAGE_KEYS.savedUsername` 代替 `'saved_username'`
4. **缓存时间**:使用 `CACHE_CONFIG.planDataDuration` 代替 `10000`
5. **向后兼容**`constants.ts` 重新导出 `animationConfig`/`paginationConfig`/`progressThresholds`,旧代码无需修改
### 设计架构
- **CSS变量体系**: 完整50-900色阶、6级阴影系统、毛玻璃/滚动条美化等自定义工具类
- **动效规范**: 页面过渡(opacity+slide, 0.35s)、列表交错(stagger 0.08)、Spring弹簧交互
- **性能降级**: `usePerformance` Hook 自动检测设备性能低配设备仅使用opacity过渡
- **响应式设计**: 移动优先,断点 sm(640)/md(768)/lg(1024)/xl(1280),桌面表格↔移动卡片自动切换
- **触控优化**: 44px最小触控区域、防双击缩放、数字键盘自动唤起
### 布局架构
| 角色 | 布局组件 | 导航项数 | 路由模式 |
|------|---------|---------|---------|
| 采购商 | PurchaserLayout | 8项 | 嵌套Outlet |
| 纺织厂 | TextileLayout | 5项 | 嵌套Outlet |
| 水洗厂 | 无独立Layout | 6项 | 扁平路由 |
### 后端服务
- **Meoo Cloud (Supabase)** - 云数据库 + 认证 + 实时订阅 + 文件存储
- **PostgreSQL** - 31张业务表支持复杂查询和事务
- **Row Level Security** - 行级安全策略,基于 company_id 的数据隔离
- **Realtime** - 实时数据同步,单例管理器 + 引用计数自动清理
- **Storage** - avatars + product_images 两个存储桶
### 数据安全
- **RLS 策略** - 所有表启用行级安全,严格的数据访问控制
- **公司隔离** - 基于 company_id + get_user_master_company_id() 的数据隔离
- **子账号支持** - 主账号/子账号权限继承master_id 关联
- **分享加密** - HMAC-SHA256签名 + Base64编码30分钟有效期
- **合作关系** - company_relationships 表实现首次合作确认机制
## 快速开始
### 环境要求
- Node.js 18+
- pnpm 8+
### 安装依赖
```bash
pnpm install
```
### 开发模式
```bash
pnpm run dev
```
服务启动在 http://localhost:3015
### 构建生产版本
```bash
pnpm run build
```
### 数据库迁移
```bash
# 查看云服务状态
meoo-cli cloud status
# 执行数据库迁移
meoo-cli cloud migrate --sql "..." --name "migration_name" --changes "变更说明"
```
## 项目结构2026-06-04 更新)
```
src/
├── App.tsx # 根组件25条HashRouter路由 + PageErrorBoundary
├── components/ # 共享组件33个
│ ├── layout/ # 布局组件3个
│ │ ├── Sidebar.tsx # 可折叠侧边栏导航
│ │ ├── PurchaserLayout.tsx # 采购商布局8项导航 + amber主题
│ │ └── TextileLayout.tsx # 纺织厂布局5项导航 + emerald主题
│ ├── warehouse/ # 仓库管理组件6个
│ │ ├── WarehouseNav.tsx # 仓库类型导航
│ │ ├── ProductForm.tsx # 产品创建/编辑表单
│ │ ├── InboundForm.tsx # 入库表单
│ │ ├── OutboundForm.tsx # 出库表单
│ │ ├── ProductList.tsx # 产品列表(桌面表格+移动卡片)
│ │ └── InboundRecords.tsx # 入库记录列表
│ ├── plans/ # 计划管理组件3个
│ │ ├── PlanGroup.tsx # 工厂分组 + 计划卡片
│ │ ├── ShareModal.tsx # 分享链接弹窗(短链+长链+隐藏敏感信息)
│ │ └── PlanEditModal.tsx # 计划编辑弹窗
│ ├── PlanCard.tsx # 计划卡片(进度条+状态+流程节点)
│ ├── ProcessFlow.tsx # 生产流程节点(呼吸动画+弹窗确认)
│ ├── ProgressBar.tsx / StatusBadge.tsx # 基础UI组件
│ ├── InventoryRecordsModal.tsx # 入库记录弹窗
│ ├── YarnAllocationModal.tsx # 纱线分配弹窗(自动/手动模式)
│ ├── NotificationCenter.tsx # 通知中心amber/emerald/violet主题
│ ├── HelpCenter.tsx / UserManual.tsx / OnboardingGuide.tsx # 帮助系统
│ ├── VersionUpdate.tsx / FeedbackModal.tsx / AboutModal # 版本与反馈
│ ├── CrashReporter.tsx / ErrorBoundary.tsx # 错误处理
│ ├── DemoDisclaimerModal.tsx / DemoWatermark.tsx # Demo标识
│ ├── PageTransition.tsx / VirtualList.tsx / Tooltip.tsx # UI增强
│ └── NetworkStatusBar.tsx / ComingSoonModal.tsx # 辅助组件
├── pages/ # 页面组件25个
│ ├── LoginPage.tsx / RegisterPage.tsx / RoleSelectPage.tsx # 认证页
│ ├── MemberManage.tsx # 子账号管理 + 帮助系统入口
│ ├── ImportPlanPage.tsx # 分享链接导入(解密+确认/拒绝)
│ ├── DemoDataSharing.tsx # 数据共享演示
│ ├── purchaser/ # 采购商页面8个PurchaserLayout嵌套
│ │ ├── Dashboard.tsx # 首页(统计+最近计划+快捷操作)
│ │ ├── PlanOverview.tsx # 纺织计划总览
│ │ ├── NewPlan.tsx / NewWashingPlan.tsx # 新建计划
│ │ ├── WarehouseManage.tsx # 产品信息管理
│ │ ├── FinishedWarehouse.tsx # 成品仓库
│ │ ├── FactoryManage.tsx # 工厂管理
│ │ └── AccountsPayable.tsx # 应付账款
│ ├── textile/ # 纺织厂页面5个TextileLayout嵌套
│ │ ├── Dashboard.tsx # 生产概览
│ │ ├── PlanOverview.tsx # 接单与生产进度
│ │ ├── YarnWarehouse.tsx # 原料纱仓库(出入库记录)
│ │ ├── FabricWarehouse.tsx # 已生产坯布Realtime订阅
│ │ └── PaymentPending.tsx # 待结款
│ └── washing/ # 水洗厂页面6个扁平路由无Layout
│ ├── Dashboard.tsx # 首页violet主题
│ ├── PlanOverview.tsx # 水洗计划总览
│ ├── PendingFabric.tsx / CompletedFabric.tsx # 待洗/已完成
│ ├── FinishedWarehouse.tsx # 成品仓库
│ └── PaymentPending.tsx # 待结款
├── hooks/ # 自定义Hooks9个
│ ├── useInventoryData.ts # 库存数据5秒缓存+Realtime
│ ├── usePlanData.ts # 计划数据10秒缓存+分页+Realtime
│ ├── usePlanStatusSync.ts # 计划状态自动同步10秒测试间隔
│ ├── useRealtime.ts # Realtime单例管理器引用计数
│ ├── useResponsive.ts # 响应式断点检测
│ ├── useTheme.ts # 主题管理暗黑模式class策略
│ ├── usePerformance.ts # 性能检测(三档动画降级)
│ ├── useNetworkStatus.ts # 网络状态监听
│ └── useVirtualScroll.ts # 虚拟滚动
├── config/app.ts # 应用全局配置中心(环境/缓存/分页/动画/主题色/存储键等)
├── contexts/AuthContext.tsx # 认证上下文login/register/logout
├── styles/index.css # 全局样式CSS变量+工具类+移动端适配)
├── supabase/ # Supabase客户端自动生成禁止修改
├── types/index.ts # 统一类型定义中心30+接口)
└── utils/ # 工具函数
├── constants.ts # 状态枚举、UI映射、步骤配置从config/app导入并重新导出
├── helpers.ts # 日期格式化、数字解析、分组计算
└── shareCrypto.ts # HMAC-SHA256签名加密
```
## 路由结构
| URL 路径 | 组件 | 布局 | 说明 |
|----------|------|------|------|
| `/login` | LoginPage | - | 登录页(演示账号+三角色主题色) |
| `/register` | RegisterPage | - | 企业注册 |
| `/role-select` | RoleSelectPage | - | 角色选择 |
| `/purchaser` | PurchaserDashboard | PurchaserLayout | 采购商首页 |
| `/purchaser/plans` | PlanOverview | PurchaserLayout | 纺织计划总览 |
| `/purchaser/plans/new` | NewPlan | PurchaserLayout | 新建纺织计划 |
| `/purchaser/washing-plans/new` | NewWashingPlan | PurchaserLayout | 新建水洗计划 |
| `/purchaser/warehouse` | WarehouseManage | PurchaserLayout | 产品信息管理 |
| `/purchaser/finished-warehouse` | FinishedWarehouse | PurchaserLayout | 成品仓库 |
| `/purchaser/factories` | FactoryManage | PurchaserLayout | 工厂管理 |
| `/purchaser/accounts-payable` | AccountsPayable | PurchaserLayout | 应付账款 |
| `/textile` | TextileDashboard | TextileLayout | 纺织厂首页 |
| `/textile/plans` | TextilePlanOverview | TextileLayout | 接单与生产进度 |
| `/textile/yarn-warehouse` | YarnWarehouse | TextileLayout | 原料纱仓库 |
| `/textile/fabric-warehouse` | FabricWarehouse | TextileLayout | 已生产坯布 |
| `/textile/payments` | PaymentPending | TextileLayout | 待结款 |
| `/washing` | WashingDashboard | - | 水洗厂首页 |
| `/washing/plans` | WashingPlanOverview | - | 水洗计划总览 |
| `/washing/pending` | PendingFabric | - | 待水洗坯布 |
| `/washing/completed` | CompletedFabric | - | 已完成水洗 |
| `/washing/finished-warehouse` | FinishedWarehouse | - | 成品仓库 |
| `/washing/payments` | WashingPaymentPending | - | 待结款 |
| `/members` | MemberManage | - | 子账号管理 |
| `/import` | ImportPlanPage | - | 分享链接导入 |
| `/demo/data-sharing` | DemoDataSharing | - | 数据共享演示 |
## 组件说明
### InventoryRecordsModal 入库记录弹窗
统一风格的入库记录详情弹窗,支持采购商和纺织厂页面复用。
**特性:**
- 统计摘要:显示总匹数和总米数
- 记录列表:按时间倒序显示所有入库记录
- 详细信息:日期时间、计划编号、工厂名称、批号、匹数、米数
- 动画效果Framer Motion 平滑动画
**使用示例:**
```tsx
import { InventoryRecordsModal } from '../../components/InventoryRecordsModal';
<InventoryRecordsModal
isOpen={recordsModalOpen}
onClose={() => setRecordsModalOpen(false)}
records={selectedRecords}
title="产品名称 - 入库记录"
/>
```
### OnboardingGuide 新用户引导
首次进入系统时展示的功能引导动画,支持采购商和纺织厂角色。
**特性:**
- 分步骤功能介绍
- 支持跳转到对应功能区
- 进度条和步骤指示器
- 可跳过引导
### DemoDisclaimerModal Demo免责声明
访问网站时显示的Demo阶段免责声明弹窗。
### ComingSoonModal 功能开发中
点击未开发功能时显示的提示弹窗。
## 使用指南
### 采购商操作流程
1. 注册/登录账号,选择"采购商"角色
2. 创建新计划,填写产品信息、纱线配比
3. 通过分享链接将计划发送给纺织厂
4. 实时查看生产进度,管理坯布库存
5. 生产完成后确认结款
### 纺织厂操作流程
1. 注册/登录账号,选择"纺织厂"角色
2. 通过分享链接或剪贴板导入计划
3. 按流程节点确认生产进度
4. 坯布入库时填写入库数量和匹数
5. 查看待结款,确认收款
### 子账号管理
- 主账号可创建子账号,分配不同权限
- 子账号可独立操作,数据归属主账号公司
- **用户名全局唯一**:子账号用户名不可与其他主账号或子账号重复
## 数据安全
- 分享链接采用加密传输,不包含敏感信息
- 导入页面隐藏成品名称、颜色、色号等敏感字段
- RLS策略确保数据隔离仅授权用户可访问
- 虚拟邮箱格式 `{username}@meoo.local` 保护隐私
## 浏览器支持
- Chrome 90+
- Safari 14+
- Firefox 88+
- Edge 90+
## 更新日志
### 2026-06-04 (v2.0.0) - 重大版本更新
- **系统审计与质量保障**
- 完成四维度系统审计(文件关联/内存安全/路由配置/权限授权),全部通过
- 新增 Bug 快速排查检查单12大类90+检查项覆盖页面白屏、数据读写、状态同步、内存性能、样式UI、认证权限、分享链接、构建部署等全部问题类型
- 新增数据库诊断常用 SQL7条和高频 Bug 速查索引14条
- 修复数据完整性问题:清理 share_links 孤儿记录、修复计划状态不一致、标记过期链接
- **文档体系完善**
- 完善数据库31张表完整文档按6大模块组织用户权限/生产计划/库存管理/财务结算/分享协作/系统辅助)
- 新增设计架构规范CSS变量体系/动效规范/响应式设计/布局架构差异)
- 新增多角色主题色系统完整文档
- API 调用示例扩展Realtime订阅/分享链接加密解密)
- **测试体系建设**
- 新增 E2E 全流程测试文件 `e2e/full-workflow.spec.ts`
- 完成采购商下单→分享链接→纺织厂确认→生产流程→分批次入库的端到端模拟测试
- 验证数据一致性completed_quantity = SUM(inventory_records.quantity)
- **代码质量**
- usePlanStatusSync 测试间隔标注10秒测试用生产环境需改回5分钟
- 项目目录结构文档更新至最新状态33组件/25页面/9 Hooks
### 2025-06-02 (v1.0.36)
- **水洗厂功能完善**
- 新增已完成坯布仓库页面,展示水洗完成的坯布库存
- 新增待水洗坯布页面,展示待水洗的坯布列表
- 新增水洗厂计划总览页面,统一管理水洗计划
- 新增水洗厂结款页面,支持查看和确认水洗费用
- **采购商功能增强**
- 新增成品仓库页面,管理已完成水洗的成品
- 新增应付账款页面,查看各工厂的应付费用
- **组件优化**
- 新增 YarnAllocationModal 组件,优化纱线分配流程
- 新增 DemoWatermark 组件Demo 模式显示水印
- 新增 PageTransition 组件,统一页面过渡动画
- 优化 VirtualList 组件,支持大数据列表虚拟滚动
- **布局优化**
- 新增 Sidebar 侧边栏组件,统一导航结构
- 新增 PurchaserLayout 采购商布局组件
- 统一各角色工作台的布局风格
### 2025-06-01 (v1.0.35)
- **分享链接自动过期机制**
- 创建 `check_share_links_expired()` 数据库函数,自动更新过期链接状态
- 完善分享链接流程,符合业务流程图要求
- 移除 `plan_factories` 表错误唯一约束 `unique_plan_factory_type`
- **系统逻辑闭环检查**
- 全面检查采购商与纺织厂关联流程
- 修复 NewPlan.tsx 子操作错误处理(纱线配比、流程节点、价格历史)
- 验证系统符合计划分享流程图和计划确认流程图
### 2025-05-30 (v1.0.34)
- **计划创建流程修复**
- 修复创建计划时自动关联工厂的问题
- 创建计划时不再自动在 `plan_factories` 表中插入关联记录
- 工厂关联改为通过分享链接或推送功能,由工厂确认后才建立
- 删除 `auto_sync_plan_trigger` 触发器,避免自动关联历史工厂
- **Bug修复**
- 修复 `factory_type` 枚举类型错误(`'textile' as FactoryType`
- 修复触发器函数 `auto_sync_plan_to_factory()` 中变量类型声明(`TEXT``factory_type`
### 2025-05-30 (v1.0.33)
- **采购商移动端UI重构**
- 移动端界面风格与纺织厂保持一致,采用卡片式布局
- 统计卡片改为3列紧凑布局与纺织厂一致
- 最近计划支持左右滑动展示,带滑动按钮和指示器
- 快捷操作区域显示6个功能按钮3列布局新建纺织计划、新建水洗计划、产品信息、水洗仓库、工厂管理、应付账款
- 背景使用渐变风格amber-50/orange-50
- **页面切换优化**
- 添加数据缓存机制dataLoaded状态避免重复加载
- 从其他页面返回时保持原有数据,不显示加载动画,页面瞬间呈现
- 添加页面可见性监听visibilitychange后台返回前台时自动刷新数据
- **Bug修复**
- 修复快捷操作路由路径错误(应付账款、水洗仓库)
- 修复CreditCard图标未导入导致的运行时错误
### 2025-05-30 (v1.0.32)
- **分享链接流程重构**
- 新增 `company_relationships` 表记录采购商与工厂的合作关系
- 重构分享逻辑已有合作关系直接推送无合作关系生成30分钟有效期的分享链接
- 新增链接状态追踪pending → clicked → confirmed/rejected/expired/cancelled
- 工厂可确认或拒绝计划,拒绝时可填写原因反馈给采购商
- 确认后自动建立合作关系,后续计划可直接推送
- 链接30分钟过期自动失效可重新生成
- **数据库 RLS 策略修复**
- 修复 `yarn_ratios` INSERT 策略缺失 WITH CHECK 条件导致 403 错误
- 简化 `share_links` SELECT 策略,避免复杂查询导致 500 错误
- 添加 `companies` DELETE 策略,支持删除工厂信息
- **Bug 修复**
- 修复 `usePlanData` Hook 依赖项导致无限循环、页面卡加载问题
- 修复删除工厂时未清理 `company_relationships` 关联导致外键约束错误
- 修复 `ShareModal``ImportPlanPage` Date 构造类型错误
- 修复计划总览 factories 查询逻辑,显示所有工厂而非仅有关联的
- **计划状态同步修复**:创建 `usePlanStatusSync` Hook每5分钟自动检查并修复计划状态不一致问题
- **分享链接导入修复**:修复导入成功后未更新 `production_plans.status``producing` 的问题
- **采购商界面优化**:计划卡片显示关联纺织厂公司名称,便于二次确认
- **水洗计划数据加载修复**:修复 RLS 策略冲突导致产品库存数据无法加载的问题
- **入库记录产品信息显示修复**:修复 `useInventoryData` 返回数据缺少产品信息导致"未知产品"显示问题
- **UI 优化**
- 采购商 Dashboard "新建水洗"更名为"新建水洗计划"
- 工厂管理添加删除功能,支持删除无关联计划的工厂
### 2025-05-28 (v1.0.31)
- **动画性能优化**
- 创建 `usePerformance` Hook自动检测设备性能级别
- 支持三种性能模式:高性能/中等性能/低性能
- 自动检测系统减少动画偏好设置
- 简化页面过渡动画,仅使用 opacity 变化
- 优化 Dashboard 页面,使用 CSS transition 替代复杂动画
- 添加 CSS 硬件加速优化GPU加速、内容可见性
- 支持低配置电脑流畅运行
- **分享链接安全修复**
- 统一加密/解密为带 HMAC-SHA256 签名的异步版本,消除同步版本无签名验证的安全隐患
- `decryptShareParams` 返回类型扩展,补回之前丢失的 `hideSensitive` 字段
- `ShareModal` 长链接 token 改为异步生成,确保签名完整性
- `ImportPlanPage` 长链接解析改为异步解密,启用签名验证
- **短链 hideSensitive 同步修复**
- 用户切换"隐藏成品信息"开关后,短链对应的 `hide_sensitive` 值实时同步到数据库
- 纺织厂通过短链导入时,敏感信息显示状态与采购商当前设置一致
- **已知未修复问题**
- `production_plans` SELECT RLS 策略过于宽松:任何登录用户可通过 `plan_factories` 存在关联这一条件查看计划详情,存在数据泄露风险
- **导入流程修复**
- 导入成功后跳转到计划总览而非 Dashboard确保用户能立即看到导入的计划
- 纺织厂计划总览添加 `plan_factories` Realtime 订阅,导入新计划后自动刷新
- **分享链接失效机制**
- `share_links` 表新增 `used_at` 字段,导入成功后标记短链为已使用
- 解析短链时检查 `used_at`,已使用的链接显示"链接已失效"提示
- 防止同一分享链接被重复导入
### 2025-05-28 (v1.0.3)
- **原料纱仓库出入库记录功能**
- 创建 `yarn_stock_records` 表,记录原料纱出入库历史
- 采纱环节自动记录出库,关联到对应生产计划
- 原料纱入库时自动记录入库
- 原料纱仓库页面新增"出入库记录"标签页
- 显示出入库类型、数量、关联计划、时间等信息
- **采纱环节优化**
- 添加自动/手动分配模式切换
- 自动匹配失败时提示切换到手动分配
- 手动模式支持输入实际使用纱线名称和重量
- 确认时显示实际消耗统计(各纱线用量+总计)
- 库存不足时强制阻止确认,必须先补充库存
- **Bug 修复**
- 修复纱线占比显示为10000%的问题
### 2025-05-27 (v1.0.2)
- **账号管理页面帮助系统集成**
- 新增"帮助与支持"卡片区域,集成用户手册、用户反馈、关于窗口
- 用户手册:详细使用指南,支持搜索功能
- 用户反馈:支持提交问题或建议到数据库
- 关于窗口:显示版本号 v1.0.2、版权信息、技术支持联系方式
- **帮助系统组件完善**
- 内置帮助中心F1快捷键功能介绍、常见操作步骤、快捷键列表
- 新手指引:首次登录自动弹窗,引导完成关键设置
- 工具提示:所有按钮悬停显示功能说明
- 版本更新检查:自动检测新版本,仅弹窗一次
- 崩溃报告系统:全局错误监听,自动收集错误日志
- **通知中心主题色适配**
- 采购商工作台琥珀色主题bg-amber-100/text-amber-700
- 纺织厂工作台翠绿色主题bg-emerald-100/text-emerald-700
- 水洗厂工作台紫色主题bg-purple-100/text-purple-700
- **计划拒绝功能优化**
- 使用 localStorage 持久化拒绝状态,跨页面保持同步
- 被拒绝的计划显示灰色卡片和"已拒绝"标签
- 被拒绝的计划自动从 Dashboard "最近计划"中移除
- 每个被拒绝的计划弹窗仅显示一次
### 2025-05-26
- **计划详情字段完善**
- 采购商和纺织厂计划总览页面统一显示所有技术字段
- 新增显示字段:克重、经线克重、纬线克重、总克重、生产采购价、产品图片、纱线配比、每米纱用量
- 新增时间字段:创建时间、计划开始时间
- 新增备注字段显示
- 纺织厂页面隐藏敏感信息(成品名称、颜色、色号)以保护采购商数据
- **移动端 UI 优化**
- 计划卡片移动端适配缩小图片尺寸64x64、字体调整为 text-xs
- 字段标签简化(如"计划编号:"→"编号:"
- 网格布局优化,避免内容溢出
- 所有工作台退出按钮在移动端变为图标形式LogOut图标
- **拒绝计划功能增强**
- 纺织厂拒绝计划后立即显示灰色卡片和"已拒绝"标签
- 被拒绝的计划自动折叠
- 被拒绝的计划从 Dashboard "最近计划"中消失
- 使用 localStorage 持久化拒绝状态,跨页面保持同步
### 2025-05-25
- **产品图片上传功能**
- 为采购商产品信息管理添加图片上传功能
- 支持在产品创建和编辑时上传产品图片JPG、PNG格式最大5MB
- 产品列表展示40x40px缩略图无图片时显示默认占位图标
- 产品表单支持图片预览、重新上传和删除功能
- 使用 Supabase Storage `product_images` 存储桶存储图片
- 数据库 `products` 表新增 `image_url` 字段
- **UI 优化**
- 纺织厂工作台"原坯布仓库"更名为"已生产坯布"(页面标题和首页快捷操作)
### 2025-05-24
- **新增出入库历史功能**
- 采购商产品信息列表新增"出入库历史"按钮
- 支持查看每个产品的完整库存变动记录(批号、匹数、米数、时间)
- 桌面端和移动端均支持
- **类型系统优化**
- 修复 `ProductInRecord` 类型定义,与数据库表结构保持一致
- 区分数据库必需字段和前端展示扩展字段
- **新增组件**
- `OutboundForm.tsx` - 出库表单组件
- `PlanEditModal.tsx` - 计划编辑弹窗
- `NotificationCenter.tsx` - 通知中心
- `NetworkStatusBar.tsx` - 网络状态栏
- `VirtualList.tsx` - 虚拟列表组件
- `ErrorBoundary.tsx` - 错误边界组件
### 2025-05-23
- 优化纺织厂工作台UI动画流畅度
- 全面适配移动端,优化触控体验
- 添加实时数据订阅,入库记录自动更新
- 优化坯布入库输入框布局
- 修复采购商仓库管理数据同步问题
- 创建统一的入库记录弹窗组件 `InventoryRecordsModal`
### 2025-05-22
- 项目初始化
- 完成基础架构搭建
- 实现用户认证系统
- 完成数据库设计和迁移
## 测试
### 类型检查
```bash
pnpm run typecheck
```
### 代码规范
```bash
pnpm run lint
```
### 构建验证
```bash
pnpm run build
```
## CI/CD 配置
项目使用 GitHub Actions 进行持续集成和部署:
### 工作流配置
```yaml
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v2
with:
version: 8
- uses: actions/setup-node@v3
with:
node-version: 18
cache: 'pnpm'
- run: pnpm install
- run: pnpm run typecheck
- run: pnpm run lint
- run: pnpm run build
```
## 环境变量配置
项目使用以下环境变量:
### 开发环境 (.env.local)
```env
# Supabase 配置
VITE_SUPABASE_URL=https://your-project.supabase.co
VITE_SUPABASE_ANON_KEY=your-anon-key
# 应用配置
VITE_APP_NAME=昱森Demo版
VITE_APP_VERSION=2.1.0
```
### 生产环境
生产环境变量通过 CI/CD 流水线注入,请勿在代码中硬编码敏感信息。
## 数据架构2026-06-04 更新)
### 数据库概览
**31张业务表**按功能分为6大模块
| 模块 | 表数量 | 核心表 |
|------|--------|--------|
| 用户与权限 | 4 | companies, profiles, company_members, company_relationships |
| 生产计划 | 5 | production_plans, plan_factories, yarn_ratios, plan_process_steps, washing_plans |
| 库存管理 | 8 | products, warehouses, inventory_records, product_inventory_records, yarn_stock, yarn_stock_records, finished_products, finished_product_inventory_records |
| 财务结算 | 5 | payments, accounts_payable, accounts_payable_items, production_price_history, product_price_history |
| 分享与协作 | 2 | share_links, notifications |
| 系统辅助 | 7 | audit_logs, user_feedback, crash_reports, product_yarn_ratios, product_outbound_records, washing_plan_completions, washing_process_steps |
### ER 关系图
```
auth.users (Supabase内置)
├── 1:1 ── profiles (用户配置, master_id支持子账号)
│ │
│ ├── N:1 ── companies (公司, role:purchaser/textile/washing)
│ │ │
│ │ ├── 1:N ── company_members (公司成员)
│ │ │
│ │ ├── 1:N ── warehouses (仓库)
│ │ │ └── 1:N ── inventory_records / yarn_stock
│ │ │
│ │ ├── 1:N ── products (产品信息)
│ │ │ ├── 1:N ── product_inventory_records
│ │ │ ├── 1:N ── product_yarn_ratios
│ │ │ └── 1:N ── product_price_history
│ │ │
│ │ └── N:M ── company_relationships (合作关系)
│ │
│ ├── 1:N ── production_plans (生产计划)
│ │ ├── 1:N ── plan_factories (关联工厂)
│ │ ├── 1:N ── yarn_ratios (纱线配比)
│ │ ├── 1:N ── plan_process_steps (流程节点)
│ │ ├── 1:N ── inventory_records (入库记录)
│ │ ├── 1:N ── payments (结款)
│ │ └── 1:N ── production_price_history
│ │
│ └── 1:N ── washing_plans (水洗计划)
│ ├── 1:N ── washing_process_steps
│ ├── 1:N ── washing_plan_completions
│ └── 1:N ── finished_products
```
### 表结构详细设计31张表
#### 一、用户与权限模块
**companies** - 公司表 (12条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| name | TEXT NOT NULL | 公司名称 |
| role | app_role NOT NULL | purchaser/textile/washing |
| address | TEXT | 公司地址 |
| contact_phone | TEXT | 联系电话 |
| created_at | TIMESTAMPTZ | now() |
**profiles** - 用户配置表 (8条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | 关联 auth.users.id |
| username | TEXT NOT NULL UNIQUE | 用户名 |
| phone | TEXT | 手机号 |
| company_id | UUID FK | 所属公司 |
| is_master | BOOLEAN NOT NULL | 是否主账号默认true |
| master_id | UUID FK | 主账号ID子账号使用 |
| display_name | TEXT | 显示名称 |
| image_url | TEXT | 头像URL |
| created_at | TIMESTAMPTZ | now() |
**company_members** - 公司成员表 (3条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| company_id | UUID FK NOT NULL | 公司ID |
| user_id | UUID FK NOT NULL | 用户ID |
| role | TEXT NOT NULL | 成员角色,默认'member' |
| created_at | TIMESTAMPTZ | now() |
**company_relationships** - 公司合作关系表 (2条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| purchaser_company_id | UUID FK NOT NULL | 采购商公司ID |
| factory_company_id | UUID FK NOT NULL | 工厂公司ID |
| factory_type | factory_type NOT NULL | textile/washing |
| status | TEXT NOT NULL | active/inactive默认'active' |
| created_at / updated_at | TIMESTAMPTZ | 时间戳 |
#### 二、生产计划模块
**production_plans** - 生产计划表 (3条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| plan_code | TEXT NOT NULL UNIQUE | 计划编号 |
| product_name | TEXT NOT NULL | 成品名称 |
| color | TEXT NOT NULL | 颜色 |
| fabric_code | TEXT NOT NULL | 坯布识别码 |
| color_code | TEXT NOT NULL | 色号,默认'01' |
| remark | TEXT | 备注 |
| purchaser_id | UUID FK NOT NULL | 采购商公司ID |
| target_quantity | INTEGER NOT NULL | 计划产量(米)默认0 |
| completed_quantity | INTEGER NOT NULL | 已完成产量(米)默认0 |
| yarn_usage_per_meter | NUMERIC | 每米纱用量(g/m)默认0 |
| production_price | NUMERIC | 生产采购价(元/米)默认0 |
| status | plan_status NOT NULL | pending/producing/completed |
| start_time | TIMESTAMPTZ | 计划开始时间 |
| created_by | UUID FK | 创建人 |
| created_at / updated_at | TIMESTAMPTZ | now() |
**plan_factories** - 计划工厂关联表 (3条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| plan_id | UUID FK NOT NULL | 计划ID |
| factory_id | UUID FK NOT NULL | 工厂公司ID |
| factory_type | factory_type NOT NULL | textile/washing |
| created_at | TIMESTAMPTZ | now() |
**yarn_ratios** - 纱线配比表 (2条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| plan_id | UUID FK NOT NULL | 计划ID |
| yarn_name | TEXT NOT NULL | 纱线名称 |
| ratio | NUMERIC NOT NULL | 配比比例默认1 |
| amount_per_meter | NUMERIC NOT NULL | 每米用量(g/m) |
| total_amount | NUMERIC NOT NULL | 总用纱量 |
| company_id | UUID FK | 公司ID |
| yarn_type | TEXT | 纱线类型,默认'all' |
| created_at | TIMESTAMPTZ | now() |
**plan_process_steps** - 计划流程节点表 (15条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| plan_id | UUID FK NOT NULL | 计划ID |
| step_type | step_type NOT NULL | confirm/yarn_purchase/dyeing/machine_start/fabric_warehouse |
| status | step_status NOT NULL | pending/active/completed/rejected |
| timestamp | TIMESTAMPTZ | 确认时间戳 |
| operator_id | UUID FK | 操作人 |
| notes | TEXT | 备注 |
| company_id | UUID FK | 公司ID |
| created_at | TIMESTAMPTZ | now() |
**washing_plans** - 水洗计划表 (1条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| plan_code | TEXT NOT NULL | 水洗计划编号 |
| company_id | UUID FK NOT NULL | 采购商公司ID |
| product_id | UUID FK NOT NULL | 产品ID |
| washing_factory_id | UUID FK | 水洗厂公司ID |
| planned_meters | NUMERIC NOT NULL | 计划水洗米数 |
| washing_price | NUMERIC NOT NULL | 水洗单价(元/米) |
| estimated_shrinkage_rate | NUMERIC NOT NULL | 预估缩水率(%) |
| estimated_washed_meters | NUMERIC | 预估洗后米数(自动计算) |
| estimated_total_cost | NUMERIC | 预估总费用(自动计算) |
| actual_shrinkage_rate | NUMERIC | 实际缩水率(%) |
| actual_washed_meters | NUMERIC | 实际洗后米数 |
| actual_total_cost | NUMERIC | 实际总费用 |
| washing_date | DATE | 水洗日期 |
| status | TEXT NOT NULL | pending/in_progress/completed |
| notes | TEXT | 备注 |
| created_by | UUID FK | 创建人 |
| created_at / updated_at | TIMESTAMPTZ | now() |
#### 三、库存管理模块
**products** - 产品信息表 (9条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| company_id | UUID FK NOT NULL | 所属公司 |
| product_name | TEXT NOT NULL | 产品名称 |
| weight | NUMERIC NOT NULL | 克重(g) |
| color | TEXT NOT NULL | 颜色 |
| fabric_code | TEXT NOT NULL | 坯布码 |
| color_code | TEXT NOT NULL | 色号,默认'01' |
| yarn_usage_per_meter | NUMERIC NOT NULL | 每米纱用量 |
| yarn_types | TEXT[] | 纱线类型数组 |
| yarn_ratios | NUMERIC[] | 纱线配比数组 |
| raw_fabric_rolls | INTEGER NOT NULL | 坯布匹数 |
| raw_fabric_meters | NUMERIC NOT NULL | 坯布米数 |
| total_stock | NUMERIC NOT NULL | 总库存 |
| production_price | NUMERIC | 生产价格 |
| image_url | TEXT | 产品图片URL |
| warp_weight | NUMERIC | 经线克重 |
| weft_weight | NUMERIC | 纬线克重 |
| total_weight | NUMERIC | 总克重 |
| created_at / updated_at | TIMESTAMPTZ | now() |
**warehouses** - 仓库表 (5条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| company_id | UUID FK NOT NULL | 所属公司 |
| name | TEXT NOT NULL | 仓库名称 |
| type | warehouse_type NOT NULL | raw_fabric/fabric/finished/yarn |
| location | TEXT | 仓库位置 |
| created_at | TIMESTAMPTZ | now() |
**inventory_records** - 入库记录表 (0条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| plan_id | UUID FK NOT NULL | 关联计划ID |
| warehouse_id | UUID FK NOT NULL | 仓库ID |
| quantity | NUMERIC NOT NULL | 入库米数 |
| rolls | INTEGER | 入库匹数 |
| warehouse_location | TEXT | 库位 |
| operator_id | UUID FK | 操作人 |
| company_id | UUID FK | 公司ID |
| price_per_meter | NUMERIC | 单价 |
| price_note | TEXT | 价格备注 |
| created_at | TIMESTAMPTZ | now() |
**product_inventory_records** - 产品出入库记录表 (4条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| product_id | UUID FK NOT NULL | 产品ID |
| warehouse_id | UUID FK | 仓库ID |
| batch_no | TEXT NOT NULL | 批号 |
| rolls | INTEGER NOT NULL | 匹数 |
| meters | NUMERIC NOT NULL | 米数 |
| operator_id | UUID FK | 操作人 |
| notes | TEXT | 备注 |
| company_id | UUID FK | 公司ID |
| created_at | TIMESTAMPTZ | now() |
**yarn_stock** - 纱线库存表 (4条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| company_id | UUID FK NOT NULL | 所属公司 |
| warehouse_id | UUID FK | 仓库ID |
| name | TEXT NOT NULL | 纱线名称 |
| spec | TEXT | 规格 |
| quantity | NUMERIC NOT NULL | 库存数量(kg) |
| min_stock | NUMERIC NOT NULL | 最低库存预警(kg) |
| unit | TEXT NOT NULL | 单位,默认'kg' |
| updated_at | TIMESTAMPTZ | now() |
**yarn_stock_records** - 纱线出入库记录表 (0条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| company_id | UUID FK NOT NULL | 公司ID |
| yarn_stock_id | UUID FK | 纱线库存ID |
| plan_id | UUID FK | 关联计划ID |
| record_type | TEXT NOT NULL | in/out |
| quantity | NUMERIC NOT NULL | 数量(kg) |
| unit | TEXT NOT NULL | 单位,默认'kg' |
| batch_no | TEXT | 批号 |
| notes | TEXT | 备注 |
| operator_id | UUID FK | 操作人 |
| created_at | TIMESTAMPTZ | now() |
**finished_products** - 成品表 (0条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| company_id | UUID FK NOT NULL | 所属公司 |
| washing_plan_id | UUID FK | 水洗计划ID |
| product_id | UUID FK | 产品ID |
| product_name / color / fabric_code / color_code | TEXT | 产品信息 |
| weight | NUMERIC | 克重 |
| washed_meters | NUMERIC NOT NULL | 洗后米数 |
| shrinkage_rate | NUMERIC NOT NULL | 缩水率 |
| rolls | INTEGER | 匹数 |
| stock_meters / stock_rolls | NUMERIC/INTEGER | 库存 |
| warehouse_id / warehouse_location | UUID/TEXT | 仓库信息 |
| washing_cost / unit_cost | NUMERIC | 成本 |
| status | TEXT NOT NULL | in_stock/out_of_stock |
| created_at / updated_at | TIMESTAMPTZ | now() |
**finished_product_inventory_records** - 成品出入库记录表 (0条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| company_id | UUID FK NOT NULL | 公司ID |
| finished_product_id | UUID FK NOT NULL | 成品ID |
| record_type | TEXT NOT NULL | in/out |
| rolls / meters | INTEGER/NUMERIC | 数量 |
| washing_completion_id | UUID FK | 水洗完成记录ID |
| related_order_id / related_order_type | UUID/TEXT | 关联订单 |
| warehouse_id / warehouse_location | UUID/TEXT | 仓库信息 |
| batch_no / notes | TEXT | 批号/备注 |
| operator_id | UUID FK | 操作人 |
| created_at | TIMESTAMPTZ | now() |
#### 四、财务结算模块
**payments** - 结款记录表 (0条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| plan_id | UUID FK NOT NULL | 关联计划ID |
| from_company_id | UUID FK NOT NULL | 付款方 |
| to_company_id | UUID FK NOT NULL | 收款方 |
| amount | NUMERIC NOT NULL | 结款金额 |
| quantity | NUMERIC NOT NULL | 结款数量(米) |
| price_per_meter | NUMERIC NOT NULL | 单价 |
| status | payment_status NOT NULL | pending/completed |
| paid_at | TIMESTAMPTZ | 结款时间 |
| created_at | TIMESTAMPTZ | now() |
**accounts_payable** - 应付账款表 (0条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| plan_id | UUID FK NOT NULL | 计划ID |
| purchaser_id | UUID FK NOT NULL | 采购商ID |
| textile_factory_id | UUID FK NOT NULL | 纺织厂ID |
| total_amount / paid_amount / unpaid_amount | NUMERIC | 金额统计 |
| total_quantity / paid_quantity / unpaid_quantity | NUMERIC | 数量统计 |
| price_per_meter | NUMERIC NOT NULL | 单价 |
| status | TEXT NOT NULL | unpaid/partial/paid |
| created_at / updated_at | TIMESTAMPTZ | now() |
**accounts_payable_items** - 应付账款明细表 (0条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| accounts_payable_id | UUID FK NOT NULL | 应付账款ID |
| inventory_record_id | UUID FK | 入库记录ID |
| quantity / rolls / price_per_meter / amount | NUMERIC/INTEGER | 明细数据 |
| status | TEXT NOT NULL | unpaid/paid |
| payment_id | UUID FK | 关联结款ID |
| created_at / paid_at | TIMESTAMPTZ | 时间戳 |
**production_price_history** - 生产价格变更历史 (3条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| plan_id | UUID FK NOT NULL | 计划ID |
| old_price / new_price / change_amount | NUMERIC NOT NULL | 价格变更 |
| operator_id / operator_name | UUID/TEXT | 操作人 |
| change_reason | TEXT | 变更原因 |
| created_at | TIMESTAMPTZ | now() |
**product_price_history** - 产品价格变更历史 (3条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| product_id | UUID FK NOT NULL | 产品ID |
| company_id | UUID FK NOT NULL | 公司ID |
| old_price / new_price / change_amount | NUMERIC NOT NULL | 价格变更 |
| operator_id / operator_name | UUID/TEXT | 操作人 |
| change_reason | TEXT | 变更原因 |
| created_at | TIMESTAMPTZ | now() |
#### 五、分享与协作模块
**share_links** - 分享链接表 (2条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| short_code | TEXT NOT NULL | 短码 |
| plan_id | UUID FK NOT NULL | 计划ID |
| factory_type | TEXT NOT NULL | textile/washing |
| created_by | UUID FK NOT NULL | 创建人 |
| expires_at | TIMESTAMPTZ | 过期时间 |
| click_count | INTEGER | 点击次数默认0 |
| hide_sensitive | BOOLEAN | 隐藏敏感信息默认false |
| used_at | TIMESTAMPTZ | 使用时间 |
| status | TEXT NOT NULL | pending/clicked/confirmed/rejected/expired/cancelled |
| clicked_at / responded_at | TIMESTAMPTZ | 时间戳 |
| response_result | TEXT | confirmed/rejected |
| reject_reason | TEXT | 拒绝原因 |
| created_at | TIMESTAMPTZ | now() |
**notifications** - 通知表 (4条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| recipient_id | UUID FK NOT NULL | 接收人 |
| sender_id / sender_company_id | UUID FK | 发送人/公司 |
| plan_id | UUID FK | 关联计划 |
| type | TEXT NOT NULL | 通知类型 |
| title / content | TEXT NOT NULL | 标题/内容 |
| is_read | BOOLEAN | 已读标记默认false |
| created_at / read_at | TIMESTAMPTZ | 时间戳 |
#### 六、系统辅助模块
**audit_logs** - 审计日志表 (0条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| user_id / company_id | UUID FK | 用户/公司 |
| action | TEXT NOT NULL | 操作类型 |
| resource_type / resource_id | TEXT/UUID | 资源类型/ID |
| details | JSONB | 详细信息 |
| ip_address / user_agent | TEXT | 请求信息 |
| created_at | TIMESTAMPTZ | now() |
**user_feedback** - 用户反馈表 (0条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| type | TEXT NOT NULL | 反馈类型 |
| content | TEXT NOT NULL | 反馈内容 |
| contact | TEXT | 联系方式 |
| user_id | UUID FK | 用户ID |
| status | TEXT NOT NULL | pending/resolved |
| created_at / updated_at | TIMESTAMPTZ | now() |
**crash_reports** - 崩溃报告表 (0条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| error_message | TEXT NOT NULL | 错误信息 |
| error_stack / component_stack | TEXT | 堆栈信息 |
| user_description | TEXT | 用户描述 |
| user_agent / url | TEXT | 环境信息 |
| user_id | UUID FK | 用户ID |
| status | TEXT NOT NULL | pending/resolved |
| created_at / updated_at | TIMESTAMPTZ | now() |
**product_yarn_ratios** - 产品纱线配比表 (13条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| product_id | UUID FK NOT NULL | 产品ID |
| yarn_name | TEXT NOT NULL | 纱线名称 |
| ratio | NUMERIC NOT NULL | 配比 |
| yarn_type | TEXT | 纱线类型,默认'all' |
| created_at | TIMESTAMPTZ | now() |
**product_outbound_records** - 产品出库记录表 (1条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| product_id | UUID FK NOT NULL | 产品ID |
| company_id | UUID FK | 公司ID |
| batch_no | TEXT NOT NULL | 批号 |
| rolls / meters | INTEGER/NUMERIC | 数量 |
| washing_plan_id | UUID FK | 水洗计划ID |
| outbound_type | TEXT NOT NULL | manual/auto |
| source_batch_id | UUID FK | 源批次ID |
| recipient_company_id / recipient_company_name | UUID/TEXT | 接收方 |
| notes / operator_id | TEXT/UUID | 备注/操作人 |
| created_at | TIMESTAMPTZ | now() |
**washing_plan_completions** - 水洗完成记录表 (0条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| company_id | UUID FK NOT NULL | 公司ID |
| washing_plan_id | UUID FK NOT NULL | 水洗计划ID |
| actual_washed_meters / actual_shrinkage_rate | NUMERIC NOT NULL | 实际数据 |
| rolls | INTEGER NOT NULL | 匹数 |
| washing_date | DATE NOT NULL | 水洗日期 |
| actual_washing_cost / unit_cost | NUMERIC | 成本 |
| warehouse_id / warehouse_location | UUID/TEXT | 仓库 |
| auto_imported | BOOLEAN | 自动导入标记 |
| finished_product_id | UUID FK | 成品ID |
| completed_by / completed_at | UUID/TIMESTAMPTZ | 完成人/时间 |
| created_at | TIMESTAMPTZ | now() |
**washing_process_steps** - 水洗流程节点表 (0条)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | gen_random_uuid() |
| washing_plan_id | UUID FK NOT NULL | 水洗计划ID |
| company_id | UUID FK NOT NULL | 公司ID |
| step_type | TEXT NOT NULL | 步骤类型 |
| status | TEXT NOT NULL | pending/completed |
| timestamp | TIMESTAMPTZ | 确认时间 |
| operator_id | UUID FK | 操作人 |
| notes | TEXT | 备注 |
| created_at / updated_at | TIMESTAMPTZ | now() |
### 自定义枚举类型
```sql
-- 应用角色(公司类型)
CREATE TYPE app_role AS ENUM ('purchaser', 'textile', 'washing');
-- 工厂类型
CREATE TYPE factory_type AS ENUM ('textile', 'washing');
-- 计划状态
CREATE TYPE plan_status AS ENUM ('pending', 'producing', 'completed');
-- 流程节点类型
CREATE TYPE step_type AS ENUM ('confirm', 'yarn_purchase', 'dyeing', 'machine_start', 'fabric_warehouse');
-- 流程节点状态
CREATE TYPE step_status AS ENUM ('pending', 'active', 'completed', 'rejected');
-- 仓库类型
CREATE TYPE warehouse_type AS ENUM ('raw_fabric', 'fabric', 'finished', 'yarn');
-- 结款状态
CREATE TYPE payment_status AS ENUM ('pending', 'completed');
```
### RLS 策略
所有表启用 Row Level Security基于 `company_id` + `get_user_master_company_id()` 进行数据隔离:
```sql
-- 示例production_plans 表 RLS 策略
CREATE POLICY company_select_plans ON production_plans
FOR SELECT USING (purchaser_id = get_user_master_company_id());
CREATE POLICY company_insert_plans ON production_plans
FOR INSERT WITH CHECK (purchaser_id = get_user_master_company_id());
```
### API 调用示例
**查询计划列表**
```typescript
const { data } = await supabase
.from('production_plans')
.select('*')
.eq('purchaser_id', companyId)
.order('created_at', { ascending: false });
```
**创建入库记录**
```typescript
await supabase.from('inventory_records').insert({
plan_id: planId,
warehouse_id: warehouseId,
quantity: quantity,
rolls: rolls,
company_id: companyId,
operator_id: userId
});
```
**实时订阅库存更新**
```typescript
// 使用单例管理器(推荐)
import { useInventoryRealtime } from '../hooks/useRealtime';
useInventoryRealtime(companyId, onDataChange);
// 或直接订阅
supabase
.channel('inventory_changes')
.on('postgres_changes', {
event: '*', schema: 'public', table: 'inventory_records'
}, callback)
.subscribe();
```
**分享链接加密**
```typescript
import { encryptShareParams, decryptShareParams } from '../utils/shareCrypto';
// 生成加密链接HMAC-SHA256签名
const token = await encryptShareParams(planId, factoryType, hideSensitive);
// 解密验证
const result = await decryptShareParams(token);
// result: { planId, factoryType, hideSensitive } | null
```
## 许可证
MIT License
## 技术支持
如有问题或建议,请联系开发团队。
---
## 常见问题与解决方案
### Q1: 页面白屏/无法加载
**可能原因**
- Webpack 热更新失败
- 类型检查错误阻止构建
- 环境变量配置错误
**解决方案**
```bash
# 1. 清除缓存重新构建
rm -rf node_modules dist
pnpm install
pnpm run dev
# 2. 检查类型错误
pnpm run typecheck
# 3. 检查环境变量
cat .env.local
```
### Q2: 数据无法保存/读取
**可能原因**
- RLS 策略限制
- 网络连接问题
- 权限不足
**解决方案**
```bash
# 1. 检查云服务状态
meoo-cli cloud status
# 2. 检查 RLS 策略
meoo-cli cloud query --sql "\dt"
meoo-cli cloud query --sql "SELECT * FROM pg_policies WHERE tablename = 'your_table'"
# 3. 检查用户权限
meoo-cli cloud query --sql "SELECT * FROM profiles WHERE id = 'your-user-id'"
```
### Q3: 移动端样式错乱
**可能原因**
- Tailwind 配置问题
- 响应式断点使用错误
- CSS 未正确加载
**解决方案**
```bash
# 1. 检查 Tailwind 配置
cat tailwind.config.js
# 2. 检查 PostCSS 配置
cat postcss.config.js
# 3. 重新构建样式
pnpm run build
```
### Q4: 实时数据不更新
**可能原因**
- Realtime 未启用
- 订阅配置错误
- 网络问题
**解决方案**
```typescript
// 检查订阅是否正确设置
const channel = supabase
.channel('table_changes')
.on('postgres_changes', {
event: '*',
schema: 'public',
table: 'your_table'
}, (payload) => {
console.log('Change received:', payload);
})
.subscribe((status) => {
console.log('Subscription status:', status);
});
```
### Q5: 开发服务器预览加载失败(沙箱环境)
**现象**
- `pnpm run dev` 启动正常,端口 3015 在监听
- 但浏览器预览无法加载curl 请求超时
**根本原因**
- 沙箱环境网络限制:`net.ipv4.conf.all.forwarding = 0`
- Webpack devServer 配置不当:`host: '127.0.0.1'` 无法在沙箱访问
**解决方案**
```javascript
// webpack.config.js - 正确配置
devServer: {
port: 3015,
host: '0.0.0.0', // 必须使用 0.0.0.0
allowedHosts: 'all',
hot: true,
historyApiFallback: true,
// 不要配置 static 和 devMiddleware
}
```
**验证方法**
```bash
# 1. 类型检查
pnpm run typecheck
# 2. 构建验证(关键)
pnpm run build
# 3. 检查产物
ls -la dist/
# 4. 启动服务器(沙箱中预览可能受限,但构建成功即可部署)
pnpm run dev
```
**注意**:沙箱环境中 curl 可能仍超时,这不影响实际部署。只要 `pnpm run build` 成功,应用即可正常发布。
---
## 性能优化建议
### 1. 图片优化
- 使用 WebP 格式
- 实现懒加载
- 使用 CDN 加速
### 2. 代码分割
```typescript
// 使用 React.lazy 进行代码分割
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));
function App() {
return (
<Suspense fallback={<Loading />}>
<HeavyComponent />
</Suspense>
);
}
```
### 3. 数据缓存
```typescript
// 使用 SWR 或 React Query 进行数据缓存
import useSWR from 'swr';
const { data, error } = useSWR('/api/data', fetcher, {
revalidateOnFocus: false,
dedupingInterval: 5000
});
```
### 4. 虚拟列表
对于大数据列表,使用虚拟列表组件避免渲染过多 DOM 节点。
---
## 安全最佳实践
### 1. 输入验证
```typescript
// 始终验证用户输入
const validateInput = (input: string): boolean => {
// 防止 XSS
const xssPattern = /<script|javascript:|onerror=/i;
if (xssPattern.test(input)) return false;
// 防止 SQL 注入(虽然 Supabase 已防护)
const sqlPattern = /(\b(SELECT|INSERT|UPDATE|DELETE|DROP|CREATE)\b)/i;
if (sqlPattern.test(input)) return false;
return true;
};
```
### 2. 敏感数据处理
```typescript
// 不要在客户端暴露敏感信息
// ❌ 错误
const apiKey = 'sk-live-xxx';
// ✅ 正确 - 使用环境变量
const apiKey = process.env.VITE_API_KEY;
```
### 3. 认证检查
```typescript
// 每个需要认证的页面都添加检查
useEffect(() => {
const checkAuth = async () => {
const { data: { user } } = await supabase.auth.getUser();
if (!user) {
navigate('/login');
}
};
checkAuth();
}, []);
```
---
## 贡献指南
### 提交代码
1. Fork 项目
2. 创建功能分支 (`git checkout -b feature/xxx`)
3. 提交更改 (`git commit -m 'Add xxx'`)
4. 推送到分支 (`git push origin feature/xxx`)
5. 创建 Pull Request
### 代码规范
- 使用 TypeScript 严格模式
- 遵循 ESLint 规则
- 编写单元测试
- 更新相关文档
### 提交信息规范
```
feat: 新增功能
fix: 修复 bug
docs: 文档更新
style: 代码格式调整
refactor: 重构代码
test: 测试相关
chore: 构建/工具相关
```