sync: update auto sync (A@67794d69b70f7d291333020c5ffd071a7836d177)

This commit is contained in:
github-actions[bot] 2026-05-26 05:15:10 +00:00
parent ad0f058baa
commit 6517a3f4cd
249 changed files with 44140 additions and 2 deletions

3
.assets_mapping Normal file
View File

@ -0,0 +1,3 @@
CLAUDE.md | 文档 | https://conversation.cdn.meoo.host/conversations/312782936418197504/file/2026-05-23/1779512821061-CLAUDE.md?auth_key=d58c5d879e91e544e0693fab745459373d600d09a97cc7811e0af491c03cbf51 | /home/project/assets/CLAUDE.md
入库流程图.docx | 文档 | https://conversation.cdn.meoo.host/conversations/312782936418197504/file/2026-05-23/1779512821057-入库流程图.docx?auth_key=800c9bb00af9dd353cdb91d1966494e87255c6ae7b7e21c6e226b58b224d89b6 | /home/project/assets/入库流程图.docx
微信图片_20260525195238_49_125.jpg | 图片 | https://conversation.cdn.meoo.host/conversations/312782936418197504/image/2026-05-25/1779711506188-微信图片_20260525195238_49_125.jpg?auth_key=55d04ced266880baebbf150fa6cb06fd546e28a2aca7fd99022b2b887e978d5f | /home/project/assets/微信图片_20260525195238_49_125.jpg

19
.env.example Normal file
View File

@ -0,0 +1,19 @@
# Supabase 配置
VITE_SUPABASE_URL=https://your-project.supabase.co
VITE_SUPABASE_ANON_KEY=your-anon-key
# 应用配置
VITE_APP_NAME=织机Demo版
VITE_APP_VERSION=1.0.0
VITE_APP_ENV=development
# 功能开关
VITE_ENABLE_ANALYTICS=false
VITE_ENABLE_SENTRY=false
# API 配置
VITE_API_TIMEOUT=30000
VITE_API_RETRY_COUNT=3
# 缓存配置
VITE_CACHE_DURATION=5000

6
.env.production Normal file
View File

@ -0,0 +1,6 @@
# 生产环境配置
VITE_APP_ENV=production
VITE_ENABLE_ANALYTICS=true
VITE_ENABLE_SENTRY=true
VITE_API_TIMEOUT=60000
VITE_CACHE_DURATION=10000

106
.gitignore vendored Normal file
View File

@ -0,0 +1,106 @@
# 通用
*.log
*.tmp
*.temp
*.swp
*.swo
*.bak
*.orig
# 环境变量与密钥
.env
.env.local
.env.*.local
*.pem
*.key
# 系统文件
.DS_Store
Thumbs.db
# 编辑器与 IDE
.idea/
.vscode/
# Node.js / JavaScript / TypeScript
node_modules/
dist/
build/
.next/
.nuxt/
.cache/
coverage/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
.pnpm-store/
# Python
__pycache__/
*.py[cod]
*.pyo
*.pyd
.pytest_cache/
.mypy_cache/
.ruff_cache/
.venv/
venv/
env/
ENV/
pip-wheel-metadata/
*.egg-info/
.coverage
htmlcov/
# Java / Kotlin
target/
*.class
*.jar
*.war
*.ear
.gradle/
out/
# Go
bin/
*.test
coverage.out
# C / C++
*.o
*.obj
*.so
*.a
*.lib
*.dll
*.dylib
*.exe
CMakeFiles/
CMakeCache.txt
cmake-build-*/
compile_commands.json
Makefile
# Rust
target/
# C#
*.user
*.suo
*.userosscache
*.sln.docstates
bin/
obj/
# Ruby & PHP / Composer`/vendor/` 仅忽略仓库根目录下的 vendor不包含 src/pages/vendor/ 等)
.bundle/
/vendor/
# OneDay 中间产物目录(文件处理时的临时文件,不需要持久化)
tmp/
# other
.stats
.config
.accesslog

0
.gitkeep Normal file
View File

1
.npmrc Normal file
View File

@ -0,0 +1 @@
registry=https://registry.npmmirror.com

View File

@ -0,0 +1,74 @@
# 分享链接导入并同步关联计划功能 - 实现计划
## 功能概述
采购商(布行)在计划总览页面可以为每个计划生成分享链接,发送给纺织厂/水洗厂。对方通过链接打开系统后,自动导入并关联该计划到自己的公司,实现跨角色协作。
## 核心流程
1. **采购商生成分享链接**:在计划总览页面,点击"分享链接"按钮生成包含计划ID的URL`#/import?plan=xxx&type=textile`
2. **工厂方打开链接**:纺织厂/水洗厂用户收到链接后打开系统识别URL参数展示计划详情和导入确认页面
3. **确认导入**:工厂方确认后,系统在 `plan_factories` 表中创建关联记录,将计划绑定到工厂公司
4. **同步生效**:导入成功后,工厂方的工作台和计划总览自动显示该计划
## 实现步骤
### 步骤1新增路由和导入页面
- 在 `App.tsx` 中添加路由:`/import``ImportPlanPage`
- 创建 `src/pages/ImportPlanPage.tsx`处理URL参数中的 `plan``type`
### 步骤2采购商计划总览 - 生成分享链接
修改 `src/pages/purchaser/PlanOverview.tsx`
- 将现有的"分享链接"按钮从工厂级别移到计划级别
- 点击后生成链接:`#/import?plan={planId}&type={factoryType}`
- 显示复制链接的弹窗,支持一键复制
### 步骤3创建 ImportPlanPage 导入确认页面
创建 `src/pages/ImportPlanPage.tsx`
- 从URL参数读取 `plan`计划ID`type`工厂类型textile/washing
- 检查用户是否已登录且角色匹配纺织厂用户只能导入textile类型水洗厂只能导入washing类型
- 展示计划详情(产品名、颜色、坯布码、计划产量、纱线配比等)
- 提供"确认导入"按钮
- 导入逻辑:向 `plan_factories` 表插入 `{plan_id, factory_id: 当前公司ID, factory_type: type}`
- 导入成功后跳转到对应工作台
### 步骤4防重复导入
- 导入前检查 `plan_factories` 是否已存在相同关联
- 如果已存在,提示"该计划已导入"并跳转到工作台
### 步骤5更新 AGENTS.md 路由表
添加 `/import` 路由记录
## 涉及文件
| 文件 | 操作 | 说明 |
|------|------|------|
| `src/App.tsx` | 编辑 | 添加 `/import` 路由 |
| `src/pages/ImportPlanPage.tsx` | 新建 | 导入确认页面 |
| `src/pages/purchaser/PlanOverview.tsx` | 编辑 | 分享链接按钮改为计划级别,添加复制链接弹窗 |
| `AGENTS.md` | 编辑 | 添加路由记录 |
## 数据库变更
无需新增表或字段。使用现有的 `plan_factories` 表存储关联关系。
## URL格式设计
```
#/import?plan={planId}&type={textile|washing}
```
- `plan`: 生产计划的UUID
- `type`: 工厂类型,决定纺织厂还是水洗厂可以导入
## ImportPlanPage 页面设计
1. 未登录 → 提示登录并跳转到 `/login`
2. 已登录但角色不匹配 → 提示角色不匹配
3. 已登录且角色匹配 → 展示计划详情 + 确认导入按钮
4. 已导入 → 提示已导入 + 跳转工作台

View File

@ -0,0 +1,20 @@
[
{
"id": "1",
"content": "修改入库记录为生产记录",
"status": "completed",
"priority": "high"
},
{
"id": "2",
"content": "修改仓库管理为生产仓库管理",
"status": "completed",
"priority": "high"
},
{
"id": "3",
"content": "修复坯布入库状态显示为进行中",
"status": "completed",
"priority": "high"
}
]

View File

@ -0,0 +1,26 @@
[
{
"id": "1",
"content": "在 App.tsx 中添加 DemoWatermark 组件",
"status": "completed",
"priority": "high"
},
{
"id": "2",
"content": "在采购商工作台添加限时免费标签",
"status": "completed",
"priority": "high"
},
{
"id": "3",
"content": "在纺织厂工作台添加限时免费标签",
"status": "completed",
"priority": "high"
},
{
"id": "4",
"content": "在水洗厂工作台添加限时免费标签",
"status": "completed",
"priority": "high"
}
]

View File

@ -0,0 +1,26 @@
[
{
"id": "1",
"content": "修改坯布入库,仓库位置默认为工厂地址或名称",
"status": "completed",
"priority": "high"
},
{
"id": "2",
"content": "添加进度97%时弹出计划完成确认",
"status": "completed",
"priority": "high"
},
{
"id": "3",
"content": "实现完成后记录锁定不可更改",
"status": "completed",
"priority": "high"
},
{
"id": "4",
"content": "运行测试验证功能正常",
"status": "completed",
"priority": "medium"
}
]

View File

@ -0,0 +1,32 @@
[
{
"id": "1",
"content": "数据库迁移:为 products 表添加图片字段",
"status": "in_progress",
"priority": "high"
},
{
"id": "2",
"content": "更新类型定义ProductWithInventory 添加图片字段",
"status": "pending",
"priority": "high"
},
{
"id": "3",
"content": "修改 ProductForm添加图片上传功能",
"status": "pending",
"priority": "high"
},
{
"id": "4",
"content": "修改 ProductList显示产品图片",
"status": "pending",
"priority": "high"
},
{
"id": "5",
"content": "修改 WarehouseManage处理图片数据",
"status": "pending",
"priority": "medium"
}
]

View File

@ -0,0 +1,32 @@
[
{
"id": "1",
"content": "修改 Product 类型添加 last_in_time 字段",
"status": "completed",
"priority": "high"
},
{
"id": "2",
"content": "修改 fetchData 查询最近入库时间",
"status": "completed",
"priority": "high"
},
{
"id": "3",
"content": "在移动端卡片显示入库时间",
"status": "completed",
"priority": "high"
},
{
"id": "4",
"content": "在桌面端表格显示入库时间",
"status": "completed",
"priority": "medium"
},
{
"id": "5",
"content": "验证修改",
"status": "completed",
"priority": "medium"
}
]

View File

@ -0,0 +1,26 @@
[
{
"content": "创建子账号管理页面 MemberManage.tsx",
"id": "1",
"priority": "high",
"status": "completed"
},
{
"content": "在 App.tsx 添加子账号管理路由",
"id": "2",
"priority": "high",
"status": "completed"
},
{
"content": "在各角色 Dashboard 添加子账号管理入口",
"id": "3",
"priority": "high",
"status": "completed"
},
{
"content": "类型检查和编译验证",
"id": "4",
"priority": "high",
"status": "completed"
}
]

View File

@ -0,0 +1,20 @@
[
{
"id": "1",
"content": "统一纺织厂仪表台与采购商仪表台设计风格",
"status": "in_progress",
"priority": "high"
},
{
"id": "2",
"content": "统一水洗厂仪表台与采购商仪表台设计风格",
"status": "pending",
"priority": "high"
},
{
"id": "3",
"content": "验证修改后的页面运行正常",
"status": "pending",
"priority": "medium"
}
]

View File

@ -0,0 +1,14 @@
[
{
"id": "1",
"content": "更新 AGENTS.md 文档",
"status": "completed",
"priority": "high"
},
{
"id": "2",
"content": "更新 README.md 文档",
"status": "completed",
"priority": "high"
}
]

View File

@ -0,0 +1,20 @@
[
{
"id": "1",
"content": "修改纺织厂PlanOverview在流程节点显示最近一次入库时间",
"status": "completed",
"priority": "high"
},
{
"id": "2",
"content": "修改采购商PlanOverview显示入库进度和最近入库时间",
"status": "completed",
"priority": "high"
},
{
"id": "3",
"content": "更新ProcessFlow组件支持显示入库时间",
"status": "completed",
"priority": "medium"
}
]

View File

@ -0,0 +1,20 @@
[
{
"id": "1",
"content": "创建采购商成品仓库页面",
"status": "completed",
"priority": "high"
},
{
"id": "2",
"content": "添加路由配置",
"status": "completed",
"priority": "high"
},
{
"id": "3",
"content": "更新采购商Dashboard导航",
"status": "completed",
"priority": "high"
}
]

View File

@ -0,0 +1,20 @@
[
{
"id": "1",
"content": "修复采购商计划详情无法展开问题",
"status": "completed",
"priority": "high"
},
{
"id": "2",
"content": "修复仓库管理入库记录详情展示",
"status": "in_progress",
"priority": "high"
},
{
"id": "3",
"content": "添加采购价变动记录功能",
"status": "pending",
"priority": "high"
}
]

View File

@ -0,0 +1,38 @@
[
{
"id": "1",
"content": "重构水洗厂 Dashboard 页面,添加快捷操作、导入关联计划、水洗记录时间戳",
"status": "in_progress",
"priority": "high"
},
{
"id": "2",
"content": "创建水洗厂待处理坯布页面",
"status": "pending",
"priority": "high"
},
{
"id": "3",
"content": "创建水洗厂已完成坯布页面(含水洗时间、缩水率记录)",
"status": "pending",
"priority": "high"
},
{
"id": "4",
"content": "创建水洗厂待结款页面",
"status": "pending",
"priority": "high"
},
{
"id": "5",
"content": "更新 App.tsx 添加新路由",
"status": "pending",
"priority": "high"
},
{
"id": "6",
"content": "验证构建和运行",
"status": "pending",
"priority": "medium"
}
]

View File

@ -0,0 +1,26 @@
[
{
"id": "1",
"content": "将分享链接加密改为 JWT 标准方案",
"status": "completed",
"priority": "high"
},
{
"id": "2",
"content": "添加 JWT token 过期时间支持",
"status": "completed",
"priority": "high"
},
{
"id": "3",
"content": "优化实时订阅,合并订阅通道",
"status": "in_progress",
"priority": "high"
},
{
"id": "4",
"content": "验证修改后代码运行正常",
"status": "pending",
"priority": "high"
}
]

View File

@ -0,0 +1,38 @@
[
{
"id": "1",
"content": "创建成品仓库表 finished_products 和 finished_inventory_records",
"status": "in_progress",
"priority": "high"
},
{
"id": "2",
"content": "创建水洗厂完成计划页面 WashingPlanComplete",
"status": "pending",
"priority": "high"
},
{
"id": "3",
"content": "实现水洗完成自动导入成品仓库逻辑",
"status": "pending",
"priority": "high"
},
{
"id": "4",
"content": "创建成品仓库管理页面 FinishedWarehouse",
"status": "pending",
"priority": "medium"
},
{
"id": "5",
"content": "更新路由和导航",
"status": "pending",
"priority": "medium"
},
{
"id": "6",
"content": "验证类型检查和功能测试",
"status": "pending",
"priority": "medium"
}
]

View File

@ -0,0 +1,44 @@
[
{
"content": "重写 LoginPage 对接 Supabase 认证",
"id": "2b",
"priority": "high",
"status": "completed"
},
{
"content": "重写 RoleSelectPage 对接真实数据",
"id": "2c",
"priority": "high",
"status": "completed"
},
{
"content": "重写采购商首页对接真实数据",
"id": "3",
"priority": "high",
"status": "in_progress"
},
{
"content": "重写计划总览/新建计划对接真实数据",
"id": "4",
"priority": "high",
"status": "pending"
},
{
"content": "重写纺织厂/水洗厂页面对接真实数据",
"id": "5",
"priority": "high",
"status": "pending"
},
{
"content": "重写仓库/工厂管理对接真实数据",
"id": "6",
"priority": "high",
"status": "pending"
},
{
"content": "类型检查和编译验证",
"id": "7",
"priority": "high",
"status": "pending"
}
]

View File

@ -0,0 +1,38 @@
[
{
"content": "优化 LoginPage 桌面端布局",
"id": "d1",
"priority": "high",
"status": "completed"
},
{
"content": "优化 RoleSelectPage 桌面端布局",
"id": "d2",
"priority": "high",
"status": "in_progress"
},
{
"content": "优化各 Dashboard 桌面端布局",
"id": "d3",
"priority": "high",
"status": "pending"
},
{
"content": "优化 PlanOverview 桌面端布局",
"id": "d4",
"priority": "high",
"status": "pending"
},
{
"content": "优化 ImportPlanPage 桌面端布局",
"id": "d5",
"priority": "medium",
"status": "pending"
},
{
"content": "类型检查和编译验证",
"id": "d6",
"priority": "high",
"status": "pending"
}
]

View File

@ -0,0 +1,20 @@
[
{
"id": "1",
"content": "修复采购商计划详情无法展开问题",
"status": "completed",
"priority": "high"
},
{
"id": "2",
"content": "修复仓库管理入库记录详情展示",
"status": "completed",
"priority": "high"
},
{
"id": "3",
"content": "添加采购价变动记录功能",
"status": "completed",
"priority": "high"
}
]

View File

@ -0,0 +1,32 @@
[
{
"id": "1",
"content": "PlanOverview.tsx 添加分页查询limit/offset",
"status": "in_progress",
"priority": "high"
},
{
"id": "2",
"content": "WarehouseManage.tsx 添加分页查询",
"status": "pending",
"priority": "high"
},
{
"id": "3",
"content": "添加分页UI组件页码/加载更多)",
"status": "pending",
"priority": "medium"
},
{
"id": "4",
"content": "优化Realtime订阅改为增量更新",
"status": "pending",
"priority": "medium"
},
{
"id": "5",
"content": "运行类型检查和测试",
"status": "pending",
"priority": "high"
}
]

View File

@ -0,0 +1,32 @@
[
{
"id": "1",
"status": "completed",
"content": "修改 Product 类型添加 last_in_time 字段",
"priority": "high"
},
{
"id": "2",
"status": "completed",
"content": "修改 fetchData 查询最近入库时间",
"priority": "high"
},
{
"id": "3",
"status": "completed",
"content": "在移动端卡片显示入库时间",
"priority": "high"
},
{
"id": "4",
"status": "completed",
"content": "在桌面端表格显示入库时间",
"priority": "medium"
},
{
"id": "5",
"status": "completed",
"content": "验证修改",
"priority": "medium"
}
]

View File

@ -0,0 +1,26 @@
[
{
"id": "1",
"content": "创建通知数据库表和RLS策略",
"status": "completed",
"priority": "high"
},
{
"id": "2",
"content": "创建通知组件和通知中心",
"status": "in_progress",
"priority": "high"
},
{
"id": "3",
"content": "在流程节点完成时发送通知",
"status": "pending",
"priority": "high"
},
{
"id": "4",
"content": "在Dashboard添加通知入口",
"status": "pending",
"priority": "medium"
}
]

View File

@ -0,0 +1,44 @@
[
{
"id": "1",
"content": "为 inventory_records 表添加 company_id 字段",
"status": "completed",
"priority": "high"
},
{
"id": "2",
"content": "为 yarn_ratios 表添加 company_id 字段",
"status": "completed",
"priority": "high"
},
{
"id": "3",
"content": "为 plan_process_steps 表添加 company_id 字段",
"status": "completed",
"priority": "high"
},
{
"id": "4",
"content": "更新 inventory_records 的 RLS 策略",
"status": "completed",
"priority": "high"
},
{
"id": "5",
"content": "更新 yarn_ratios 的 RLS 策略",
"status": "completed",
"priority": "high"
},
{
"id": "6",
"content": "更新 plan_process_steps 的 RLS 策略",
"status": "completed",
"priority": "high"
},
{
"id": "7",
"content": "同步更新现有数据的 company_id",
"status": "completed",
"priority": "high"
}
]

View File

@ -0,0 +1,14 @@
[
{
"content": "修改 FactoryManage 添加新建工厂按钮和弹窗",
"id": "1",
"priority": "high",
"status": "in_progress"
},
{
"content": "类型检查和编译验证",
"id": "2",
"priority": "high",
"status": "pending"
}
]

View File

@ -0,0 +1,20 @@
[
{
"id": "1",
"content": "修改 WarehouseManage.tsx 数据获取逻辑,按工厂分组汇总",
"status": "completed",
"priority": "high"
},
{
"id": "2",
"content": "修改入库记录展示,按工厂分组显示",
"status": "completed",
"priority": "high"
},
{
"id": "3",
"content": "更新产品库存统计,显示各工厂明细",
"status": "completed",
"priority": "high"
}
]

View File

@ -0,0 +1,26 @@
[
{
"id": "1",
"content": "创建水洗厂计划总览页面 WashingPlanOverview.tsx",
"status": "in_progress",
"priority": "high"
},
{
"id": "2",
"content": "创建水洗厂仓库管理页面 WashingWarehouse.tsx",
"status": "pending",
"priority": "high"
},
{
"id": "3",
"content": "更新 App.tsx 添加水洗厂路由",
"status": "pending",
"priority": "high"
},
{
"id": "4",
"content": "更新 Dashboard.tsx 修正快捷操作路径",
"status": "pending",
"priority": "medium"
}
]

View File

@ -0,0 +1,32 @@
[
{
"id": "1",
"content": "优化登录页移动端适配",
"status": "completed",
"priority": "high"
},
{
"id": "2",
"content": "优化仪表盘移动端适配",
"status": "in_progress",
"priority": "high"
},
{
"id": "3",
"content": "优化计划总览移动端适配",
"status": "pending",
"priority": "high"
},
{
"id": "4",
"content": "优化仓库管理移动端适配",
"status": "pending",
"priority": "high"
},
{
"id": "5",
"content": "验证所有修改",
"status": "pending",
"priority": "high"
}
]

View File

@ -0,0 +1,38 @@
[
{
"id": "1",
"content": "读取存储相关文档,了解图片上传实现方式",
"status": "completed",
"priority": "high"
},
{
"id": "2",
"content": "查看现有产品管理相关代码和数据结构",
"status": "completed",
"priority": "high"
},
{
"id": "3",
"content": "创建数据库迁移 - 添加产品图片字段和存储桶",
"status": "completed",
"priority": "high"
},
{
"id": "4",
"content": "修改产品列表组件 - 添加图片展示和上传功能",
"status": "completed",
"priority": "high"
},
{
"id": "5",
"content": "修改产品表单组件 - 添加图片上传功能",
"status": "completed",
"priority": "high"
},
{
"id": "6",
"content": "验证功能并运行测试",
"status": "completed",
"priority": "medium"
}
]

View File

@ -0,0 +1,32 @@
[
{
"id": "1",
"content": "修复 useTheme hook 类型定义",
"status": "completed",
"priority": "high"
},
{
"id": "2",
"content": "修复测试文件类型错误",
"status": "completed",
"priority": "high"
},
{
"id": "3",
"content": "修复 ImportPlanPage 类型错误",
"status": "completed",
"priority": "high"
},
{
"id": "4",
"content": "修复 MemberManage 类型错误",
"status": "completed",
"priority": "high"
},
{
"id": "5",
"content": "验证修复结果",
"status": "completed",
"priority": "high"
}
]

View File

@ -0,0 +1,56 @@
[
{
"id": "1",
"content": "读取数据库参考文档了解RLS策略规范",
"status": "completed",
"priority": "high"
},
{
"id": "2",
"content": "创建成品仓库表 finished_products 及相关表结构",
"status": "completed",
"priority": "high"
},
{
"id": "3",
"content": "创建水洗计划完成记录表 washing_plan_completions",
"status": "completed",
"priority": "high"
},
{
"id": "4",
"content": "创建自动导入成品仓库的数据库函数",
"status": "completed",
"priority": "high"
},
{
"id": "5",
"content": "更新类型定义文件",
"status": "completed",
"priority": "high"
},
{
"id": "6",
"content": "创建水洗厂计划完成页面UI",
"status": "completed",
"priority": "medium"
},
{
"id": "7",
"content": "创建成品仓库管理页面",
"status": "completed",
"priority": "medium"
},
{
"id": "8",
"content": "更新路由配置",
"status": "completed",
"priority": "medium"
},
{
"id": "9",
"content": "验证功能并运行测试",
"status": "completed",
"priority": "low"
}
]

View File

@ -0,0 +1,38 @@
[
{
"id": "1",
"content": "读取 meoo-cloud Edge Functions 参考文档",
"status": "completed",
"priority": "high"
},
{
"id": "2",
"content": "创建入库事务处理 Edge Function",
"status": "completed",
"priority": "high"
},
{
"id": "3",
"content": "创建数据校验修复 Edge Function",
"status": "completed",
"priority": "high"
},
{
"id": "4",
"content": "修改前端入库逻辑调用 Edge Function",
"status": "completed",
"priority": "high"
},
{
"id": "5",
"content": "部署 Edge Functions",
"status": "completed",
"priority": "high"
},
{
"id": "6",
"content": "验证功能",
"status": "completed",
"priority": "medium"
}
]

View File

@ -0,0 +1,38 @@
[
{
"id": "1",
"content": "查看纺织厂工作台当前代码结构",
"status": "completed",
"priority": "high"
},
{
"id": "2",
"content": "查看现有YarnWarehouse页面结构",
"status": "completed",
"priority": "high"
},
{
"id": "3",
"content": "创建原坯布仓库页面",
"status": "completed",
"priority": "high"
},
{
"id": "4",
"content": "修改纺织厂工作台添加两个仓库快捷操作",
"status": "completed",
"priority": "high"
},
{
"id": "5",
"content": "添加路由配置",
"status": "completed",
"priority": "high"
},
{
"id": "6",
"content": "验证所有修改",
"status": "completed",
"priority": "high"
}
]

View File

@ -0,0 +1,26 @@
[
{
"id": "1",
"content": "创建产品价格变更历史表",
"status": "completed",
"priority": "high"
},
{
"id": "2",
"content": "执行数据库迁移",
"status": "completed",
"priority": "high"
},
{
"id": "3",
"content": "修改产品编辑逻辑,记录价格变更",
"status": "completed",
"priority": "high"
},
{
"id": "4",
"content": "在产品详情中显示价格变更历史",
"status": "completed",
"priority": "medium"
}
]

View File

@ -0,0 +1,20 @@
[
{
"id": "1",
"content": "更新 AGENTS.md 记录 webpack devServer 预览加载失败问题",
"status": "completed",
"priority": "high"
},
{
"id": "2",
"content": "更新 README.md 添加问题排查和解决方案",
"status": "completed",
"priority": "high"
},
{
"id": "3",
"content": "总结学习反思",
"status": "completed",
"priority": "medium"
}
]

View File

@ -0,0 +1,26 @@
[
{
"id": "1",
"content": "数据库迁移profiles 表添加 display_name 字段",
"status": "completed",
"priority": "high"
},
{
"id": "2",
"content": "修改注册逻辑:存储用户名到 username姓名到 display_name",
"status": "completed",
"priority": "high"
},
{
"id": "3",
"content": "修改账号管理:显示和编辑 display_name",
"status": "completed",
"priority": "high"
},
{
"id": "4",
"content": "修改首页副标题:引用 display_name 而非 username",
"status": "completed",
"priority": "high"
}
]

View File

@ -0,0 +1,38 @@
[
{
"id": "1",
"content": "创建产品定义相关数据库表products, product_yarn_ratios, fabric_batches",
"status": "completed",
"priority": "high"
},
{
"id": "2",
"content": "更新仓库管理页为三级菜单结构",
"status": "completed",
"priority": "high"
},
{
"id": "3",
"content": "实现产品管理功能(列表、新建、编辑)",
"status": "completed",
"priority": "high"
},
{
"id": "4",
"content": "实现原坯布入库功能(关联产品、记录批号和时间戳)",
"status": "completed",
"priority": "high"
},
{
"id": "5",
"content": "更新路由配置",
"status": "completed",
"priority": "medium"
},
{
"id": "6",
"content": "运行测试验证",
"status": "completed",
"priority": "medium"
}
]

View File

@ -0,0 +1,56 @@
[
{
"id": "1",
"content": "检查 RLS 策略对数据查询的影响",
"status": "completed",
"priority": "high"
},
{
"id": "2",
"content": "检查 RLS 策略对数据插入的影响",
"status": "completed",
"priority": "high"
},
{
"id": "3",
"content": "检查 RLS 策略对数据更新的影响",
"status": "completed",
"priority": "high"
},
{
"id": "4",
"content": "修复 plan_process_steps 查询策略",
"status": "completed",
"priority": "high"
},
{
"id": "5",
"content": "修复 inventory_records 插入策略",
"status": "completed",
"priority": "high"
},
{
"id": "6",
"content": "修复 payments 插入策略",
"status": "completed",
"priority": "high"
},
{
"id": "7",
"content": "修复 yarn_ratios 删除策略",
"status": "completed",
"priority": "high"
},
{
"id": "8",
"content": "修复 plan_process_steps 查询策略",
"status": "completed",
"priority": "high"
},
{
"id": "9",
"content": "验证修复后的功能",
"status": "completed",
"priority": "high"
}
]

View File

@ -0,0 +1,20 @@
[
{
"id": "1",
"content": "修改纺织厂PlanOverview在流程节点显示最近一次入库时间",
"status": "completed",
"priority": "high"
},
{
"id": "2",
"content": "修改采购商PlanOverview显示入库进度和最近入库时间",
"status": "in_progress",
"priority": "high"
},
{
"id": "3",
"content": "更新ProcessFlow组件支持显示入库时间",
"status": "completed",
"priority": "medium"
}
]

View File

@ -0,0 +1,20 @@
[
{
"id": "1",
"content": "修复导入计划页面支持水洗厂",
"status": "completed",
"priority": "high"
},
{
"id": "2",
"content": "添加水洗计划分享链接生成",
"status": "completed",
"priority": "high"
},
{
"id": "3",
"content": "验证数据同步机制",
"status": "in_progress",
"priority": "high"
}
]

View File

@ -0,0 +1,32 @@
[
{
"id": "1",
"content": "阅读采购商工作台 Dashboard 和仓库管理相关代码",
"status": "completed",
"priority": "high"
},
{
"id": "2",
"content": "设计水洗计划数据库表结构",
"status": "completed",
"priority": "high"
},
{
"id": "3",
"content": "创建新建水洗计划页面组件",
"status": "completed",
"priority": "high"
},
{
"id": "4",
"content": "添加路由配置",
"status": "completed",
"priority": "medium"
},
{
"id": "5",
"content": "在 Dashboard 添加入口按钮",
"status": "completed",
"priority": "medium"
}
]

1800
AGENTS.md Normal file

File diff suppressed because it is too large Load Diff

690
README.md
View File

@ -1,2 +1,688 @@
# iloom-flatten # 纺织行业采购计划管理系统
auto sync from kihaneseifu/iloom
一款专为纺织行业设计的全流程协作管理平台,连接采购商(布行)、纺织厂、水洗厂三方,实现从计划制定到成品交付的数字化管理。
## 核心功能
### 多角色协作
- **采购商/布行**:创建生产计划、管理坯布库存、跟踪生产进度、处理结款
- **纺织厂**:接收生产计划、管理生产流程、坯布入库、纱线库存管理
- **水洗厂**:接收水洗订单、管理水洗流程
### 计划管理
- 自动生成唯一计划编号和坯布识别码
- 纱线配比配置与用量自动计算
- 生产流程节点跟踪(确认计划 → 采纱 → 染纱 → 上机 → 坯布入库)
- 实时进度可视化支持97%完成度自动提醒
### 库存管理
- **原坯布仓库**:按坯布码分组管理,入库记录追溯
- 产品管理:支持按名称、克重、颜色多级分组展示
- 出入库历史:查看每个产品的完整库存变动记录
- 价格历史:追踪采购价格变动
- **原料纱仓库**:库存预警、最低库存提醒
- 实时库存数据同步,入库自动更新
### 结款管理
- 按完成米数自动计算结款金额
- 待结款汇总统计
- 一键确认结款,记录结款时间
### 分享与导入
- 加密分享链接,保护敏感信息
- 支持剪贴板自动识别导入
- 扫码或链接快速关联计划
## 技术特性
### 前端技术栈
- **React 18** + TypeScript - 类型安全的函数组件开发
- **TailwindCSS** - 原子化CSS快速构建响应式界面
- **Framer Motion** - 流畅的页面过渡和交互动画
- **Lucide React** - 现代化图标库
### 移动端优化
- 响应式布局,适配手机、平板、桌面端
- 触控优化44px最小触控区域、防双击缩放
- 输入优化:数字键盘自动唤起、输入模式适配
- 动画优化:硬件加速、自然动画曲线
### 后端服务
- **Meoo Cloud (Supabase)** - 云数据库 + 认证 + 实时订阅
- **PostgreSQL** - 关系型数据库,支持复杂查询
- **Row Level Security** - 行级安全策略,基于公司 ID 的数据隔离
- **Realtime** - 实时数据同步,入库记录即时更新
### 数据安全
- **RLS 策略** - 所有表启用行级安全,严格的数据访问控制
- **公司隔离** - 基于 company_id 的数据隔离,确保数据安全
- **子账号支持** - 主账号/子账号权限继承,统一公司数据访问
- **分享加密** - 分享链接使用 Base64 + 盐值混淆加密,保护敏感信息
## 快速开始
### 环境要求
- 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 "变更说明"
```
## 项目结构
```
src/
├── components/ # 公共组件
│ ├── ProcessFlow.tsx # 生产流程节点
│ ├── PlanCard.tsx # 计划卡片
│ ├── StatusBadge.tsx # 状态标签
│ ├── InventoryRecordsModal.tsx # 入库记录弹窗
│ ├── OnboardingGuide.tsx # 新用户引导
│ ├── DemoDisclaimerModal.tsx # Demo免责声明
│ └── ComingSoonModal.tsx # 功能开发中提示
├── pages/ # 页面组件
│ ├── purchaser/ # 采购商页面
│ │ ├── Dashboard.tsx
│ │ ├── PlanOverview.tsx
│ │ ├── NewPlan.tsx
│ │ ├── WarehouseManage.tsx
│ │ └── FactoryManage.tsx
│ ├── textile/ # 纺织厂页面
│ │ ├── Dashboard.tsx
│ │ ├── PlanOverview.tsx
│ │ ├── YarnWarehouse.tsx
│ │ ├── FabricWarehouse.tsx
│ │ └── PaymentPending.tsx
│ ├── washing/ # 水洗厂页面
│ │ └── Dashboard.tsx
│ ├── LoginPage.tsx
│ ├── RegisterPage.tsx
│ ├── RoleSelectPage.tsx
│ ├── MemberManage.tsx
│ └── ImportPlanPage.tsx
├── hooks/ # 自定义Hooks
│ ├── useResponsive.ts # 响应式检测
│ └── useTheme.ts # 主题管理
├── contexts/ # React上下文
│ └── AuthContext.tsx # 认证上下文
├── styles/ # 全局样式
│ └── index.css
├── supabase/ # Supabase客户端
│ ├── client.ts
│ └── types.ts
└── utils/ # 工具函数
├── crypto.ts
└── shareCrypto.ts
```
## 组件说明
### 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+
## 更新日志
### 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=1.0.0
```
### 生产环境
生产环境变量通过 CI/CD 流水线注入,请勿在代码中硬编码敏感信息。
## API 文档
### Supabase 数据库 Schema
#### 核心表结构
**companies** - 公司表
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID | 主键 |
| name | TEXT | 公司名称 |
| role | app_role | 角色purchaser/textile/washing |
| address | TEXT | 地址 |
| contact_phone | TEXT | 联系电话 |
**production_plans** - 生产计划表
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID | 主键 |
| plan_code | TEXT | 计划编号 |
| product_name | TEXT | 产品名称 |
| color | TEXT | 颜色 |
| fabric_code | TEXT | 坯布码 |
| color_code | TEXT | 色号 |
| purchaser_id | UUID | 采购商ID |
| target_quantity | INTEGER | 计划产量 |
| completed_quantity | INTEGER | 已完成产量 |
| status | plan_status | 状态 |
**plan_factories** - 计划工厂关联表
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID | 主键 |
| plan_id | UUID | 计划ID |
| factory_id | UUID | 工厂ID |
| factory_type | factory_type | 工厂类型 |
**inventory_records** - 入库记录表
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID | 主键 |
| plan_id | UUID | 计划ID |
| warehouse_id | UUID | 仓库ID |
| quantity | DECIMAL | 入库数量 |
| rolls | INTEGER | 入库匹数 |
| operator_id | UUID | 操作人ID |
**product_inventory_records** - 产品出入库记录表
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID | 主键 |
| product_id | UUID | 产品ID |
| company_id | UUID | 公司ID |
| batch_no | TEXT | 批号 |
| rolls | INTEGER | 匹数 |
| meters | DECIMAL | 米数 |
| notes | TEXT | 备注 |
| operator_id | UUID | 操作人ID |
| created_at | TIMESTAMPTZ | 创建时间 |
### 枚举类型
```sql
-- 应用角色
app_role: purchaser | textile | washing
-- 计划状态
plan_status: pending | producing | completed
-- 工厂类型
factory_type: textile | washing
-- 仓库类型
warehouse_type: raw_fabric | fabric | finished | yarn
-- 结款状态
payment_status: pending | completed
```
### RLS 策略
所有表启用 Row Level Security基于 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,
operator_id: userId
});
```
**实时订阅库存更新**
```typescript
supabase
.channel('inventory_changes')
.on('postgres_changes', {
event: '*',
schema: 'public',
table: 'inventory_records'
}, callback)
.subscribe();
```
## 许可证
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: 构建/工具相关
```

65
assets/CLAUDE.md Normal file
View File

@ -0,0 +1,65 @@
# CLAUDE.md
Behavioral guidelines to reduce common LLM coding mistakes. Merge with project-specific instructions as needed.
**Tradeoff:** These guidelines bias toward caution over speed. For trivial tasks, use judgment.
## 1. Think Before Coding
**Don't assume. Don't hide confusion. Surface tradeoffs.**
Before implementing:
- State your assumptions explicitly. If uncertain, ask.
- If multiple interpretations exist, present them - don't pick silently.
- If a simpler approach exists, say so. Push back when warranted.
- If something is unclear, stop. Name what's confusing. Ask.
## 2. Simplicity First
**Minimum code that solves the problem. Nothing speculative.**
- No features beyond what was asked.
- No abstractions for single-use code.
- No "flexibility" or "configurability" that wasn't requested.
- No error handling for impossible scenarios.
- If you write 200 lines and it could be 50, rewrite it.
Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify.
## 3. Surgical Changes
**Touch only what you must. Clean up only your own mess.**
When editing existing code:
- Don't "improve" adjacent code, comments, or formatting.
- Don't refactor things that aren't broken.
- Match existing style, even if you'd do it differently.
- If you notice unrelated dead code, mention it - don't delete it.
When your changes create orphans:
- Remove imports/variables/functions that YOUR changes made unused.
- Don't remove pre-existing dead code unless asked.
The test: Every changed line should trace directly to the user's request.
## 4. Goal-Driven Execution
**Define success criteria. Loop until verified.**
Transform tasks into verifiable goals:
- "Add validation" → "Write tests for invalid inputs, then make them pass"
- "Fix the bug" → "Write a test that reproduces it, then make it pass"
- "Refactor X" → "Ensure tests pass before and after"
For multi-step tasks, state a brief plan:
```
1. [Step] → verify: [check]
2. [Step] → verify: [check]
3. [Step] → verify: [check]
```
Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification.
---
**These guidelines are working if:** fewer unnecessary changes in diffs, fewer rewrites due to overcomplication, and clarifying questions come before implementation rather than after mistakes.

BIN
assets/入库流程图.docx Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

18
e2e/auth.setup.ts Normal file
View File

@ -0,0 +1,18 @@
import { test as setup } from '@playwright/test';
const authFile = 'e2e/.auth/user.json';
setup('authenticate', async ({ page }) => {
// 这里可以设置测试账号的登录状态
// 实际项目中应该使用测试账号登录并保存状态
// 示例:登录流程
// await page.goto('/login');
// await page.fill('[name="username"]', 'test-user');
// await page.fill('[name="password"]', 'test-password');
// await page.click('button[type="submit"]');
// await page.waitForURL('/purchaser');
// 保存登录状态
// await page.context().storageState({ path: authFile });
});

View File

@ -0,0 +1,182 @@
import { test, expect } from '@playwright/test';
/**
*
*
*
*
*
*/
test.describe('协作流程 - 采购商视角', () => {
test.beforeEach(async ({ page }) => {
// 登录采购商账号(需要配置测试账号)
await page.goto('/login');
// await loginAsPurchaser(page);
});
test('采购商创建新计划', async ({ page }) => {
// 导航到新建计划页面
await page.goto('/purchaser/plans/new');
// 验证页面加载
await expect(page.locator('h1')).toContainText('新建纺织计划');
// 填写计划表单
await page.fill('[name="productName"]', '测试产品');
await page.fill('[name="color"]', '红色');
await page.fill('[name="targetQuantity"]', '1000');
// 添加纱线配比
await page.click('text=添加纱线');
await page.fill('[name="yarnName"]', '测试纱线');
await page.fill('[name="ratio"]', '100');
// 提交表单
// await page.click('button[type="submit"]');
// 验证创建成功
// await expect(page).toHaveURL(/.*purchaser\/plans/);
});
test('采购商查看计划列表', async ({ page }) => {
await page.goto('/purchaser/plans');
// 验证页面加载
await expect(page.locator('h1')).toContainText('计划总览');
// 验证计划列表存在
await expect(page.locator('[data-testid="plan-list"]')).toBeVisible();
});
test('采购商查看库存', async ({ page }) => {
await page.goto('/purchaser/warehouse');
// 验证页面加载
await expect(page.locator('h1')).toContainText('仓库管理');
// 验证库存列表
await expect(page.locator('[data-testid="inventory-list"]')).toBeVisible();
});
});
test.describe('协作流程 - 纺织厂视角', () => {
test.beforeEach(async ({ page }) => {
// 登录纺织厂账号
await page.goto('/login');
// await loginAsTextileFactory(page);
});
test('纺织厂查看计划', async ({ page }) => {
await page.goto('/textile/plans');
// 验证页面加载
await expect(page.locator('h1')).toContainText('计划总览');
// 验证计划列表
await expect(page.locator('[data-testid="plan-list"]')).toBeVisible();
});
test('纺织厂确认流程节点', async ({ page }) => {
await page.goto('/textile/plans');
// 找到待确认的计划
const pendingPlan = page.locator('[data-testid="plan-card"]').first();
await expect(pendingPlan).toBeVisible();
// 展开计划详情
await pendingPlan.click();
// 点击确认按钮
// await page.click('[data-testid="confirm-step-button"]');
// 验证确认成功
// await expect(page.locator('[data-testid="step-completed"]')).toBeVisible();
});
test('纺织厂坯布入库', async ({ page }) => {
await page.goto('/textile/plans');
// 找到进行中的计划
const activePlan = page.locator('[data-testid="plan-card"]').first();
await expect(activePlan).toBeVisible();
// 展开计划
await activePlan.click();
// 填写入库信息
// await page.fill('[data-testid="inbound-quantity"]', '100');
// await page.fill('[data-testid="inbound-rolls"]', '10');
// 提交入库
// await page.click('[data-testid="submit-inbound"]');
// 验证入库成功
// await expect(page.locator('[data-testid="inbound-success"]')).toBeVisible();
});
test('纺织厂查看坯布仓库', async ({ page }) => {
await page.goto('/textile/fabric-warehouse');
// 验证页面加载
await expect(page.locator('h1')).toContainText('原坯布仓库');
// 验证库存列表
await expect(page.locator('[data-testid="fabric-inventory"]')).toBeVisible();
});
});
test.describe('数据同步验证', () => {
test('入库后采购商实时看到库存更新', async ({ page, browser }) => {
// 这个测试需要两个浏览器上下文模拟两个角色
const purchaserContext = await browser.newContext();
const textileContext = await browser.newContext();
const purchaserPage = await purchaserContext.newPage();
const textilePage = await textileContext.newPage();
try {
// 采购商查看初始库存
await purchaserPage.goto('/purchaser/warehouse');
// const initialInventory = await getInventoryCount(purchaserPage);
// 纺织厂执行入库
await textilePage.goto('/textile/plans');
// await textilePage.click('[data-testid="inbound-button"]');
// await textilePage.fill('[data-testid="quantity"]', '100');
// await textilePage.click('[data-testid="submit"]');
// 等待实时同步
await purchaserPage.waitForTimeout(2000);
// 验证采购商看到更新后的库存
// const updatedInventory = await getInventoryCount(purchaserPage);
// expect(updatedInventory).toBe(initialInventory + 100);
} finally {
await purchaserContext.close();
await textileContext.close();
}
});
});
test.describe('分享链接流程', () => {
test('通过分享链接导入计划', async ({ page }) => {
// 访问分享链接
const shareToken = 'test-token';
await page.goto(`/import?token=${shareToken}`);
// 验证导入页面加载
await expect(page.locator('h1')).toContainText('导入计划');
// 验证计划信息展示(不包含敏感信息)
await expect(page.locator('[data-testid="plan-code"]')).toBeVisible();
await expect(page.locator('[data-testid="fabric-code"]')).toBeVisible();
// 确认导入
// await page.click('[data-testid="confirm-import"]');
// 验证导入成功
// await expect(page).toHaveURL(/.*textile\/plans/);
});
});

149
e2e/core-workflow.spec.ts Normal file
View File

@ -0,0 +1,149 @@
import { test, expect } from '@playwright/test';
test.describe('核心业务流程', () => {
test.beforeEach(async ({ page }) => {
// 每个测试前导航到登录页
await page.goto('/login');
});
test('采购商登录并查看仪表盘', async ({ page }) => {
// 验证登录页面加载
await expect(page).toHaveURL(/.*login/);
await expect(page.locator('h1')).toContainText('登录');
// 由于需要真实账号,这里只验证页面结构
await expect(page.locator('input[name="username"]')).toBeVisible();
await expect(page.locator('input[name="password"]')).toBeVisible();
await expect(page.locator('button[type="submit"]')).toBeVisible();
});
test('角色选择页面', async ({ page }) => {
await page.goto('/role-select');
// 验证角色选择页面
await expect(page.locator('h1')).toContainText('选择角色');
await expect(page.locator('text=采购商/布行')).toBeVisible();
await expect(page.locator('text=纺织厂')).toBeVisible();
await expect(page.locator('text=水洗厂')).toBeVisible();
});
test('注册页面表单验证', async ({ page }) => {
await page.goto('/register');
// 验证注册页面
await expect(page.locator('h1')).toContainText('注册');
// 尝试提交空表单
await page.click('button[type="submit"]');
// 验证表单验证(假设有必填验证)
await expect(page.locator('input[name="username"]')).toBeVisible();
await expect(page.locator('input[name="password"]')).toBeVisible();
await expect(page.locator('input[name="confirmPassword"]')).toBeVisible();
});
test('页面导航和路由', async ({ page }) => {
// 测试路由导航
await page.goto('/login');
await expect(page).toHaveURL(/.*login/);
// 测试 404 回退
await page.goto('/non-existent-page');
// 应该显示登录页或 404
await expect(page.locator('body')).toBeVisible();
});
test('响应式布局 - 移动端适配', async ({ page }) => {
// 设置移动端视口
await page.setViewportSize({ width: 375, height: 667 });
await page.goto('/login');
// 验证移动端布局
await expect(page.locator('body')).toBeVisible();
// 检查是否有移动端特定的样式或元素
const body = page.locator('body');
await expect(body).toBeVisible();
});
test('网络状态提示组件', async ({ page }) => {
await page.goto('/login');
// 模拟离线状态
await page.context().setOffline(true);
// 等待离线提示出现
await page.waitForTimeout(500);
// 恢复网络
await page.context().setOffline(false);
});
});
test.describe('页面加载性能', () => {
test('首页加载时间', async ({ page }) => {
const startTime = Date.now();
await page.goto('/login');
const loadTime = Date.now() - startTime;
// 验证页面在合理时间内加载
expect(loadTime).toBeLessThan(5000);
// 验证关键元素渲染
await expect(page.locator('h1')).toBeVisible();
});
test('资源加载无错误', async ({ page }) => {
const errors: string[] = [];
page.on('console', (msg) => {
if (msg.type() === 'error') {
errors.push(msg.text());
}
});
page.on('pageerror', (error) => {
errors.push(error.message);
});
await page.goto('/login');
await page.waitForLoadState('networkidle');
// 允许一些预期的错误(如 API 调用)
const unexpectedErrors = errors.filter(e =>
!e.includes('supabase') &&
!e.includes('api') &&
!e.includes('favicon')
);
expect(unexpectedErrors).toHaveLength(0);
});
});
test.describe('无障碍测试', () => {
test('登录页表单可访问性', async ({ page }) => {
await page.goto('/login');
// 检查表单元素是否有正确的标签
const usernameInput = page.locator('input[name="username"]');
const passwordInput = page.locator('input[name="password"]');
await expect(usernameInput).toHaveAttribute('placeholder');
await expect(passwordInput).toHaveAttribute('placeholder');
// 检查按钮可点击
const submitButton = page.locator('button[type="submit"]');
await expect(submitButton).toBeEnabled();
});
test('键盘导航', async ({ page }) => {
await page.goto('/login');
// 使用 Tab 键导航
await page.keyboard.press('Tab');
await expect(page.locator('input[name="username"]"]')).toBeFocused();
await page.keyboard.press('Tab');
await expect(page.locator('input[name="password"]"]')).toBeFocused();
});
});

View File

@ -0,0 +1,176 @@
// 数据一致性校验与修复 Edge Function
// 定期检查并修复 completed_quantity 与 inventory_records 不一致的问题
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
Deno.serve(async (req) => {
// CORS 预检
if (req.method === 'OPTIONS') {
return new Response('ok', {
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
},
});
}
const corsHeaders = {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
};
try {
const body = await req.json();
const { action, planId } = body; // action: 'check' | 'fix' | 'check-all'
// 获取认证信息
const authHeader = req.headers.get('Authorization') || '';
// 创建管理员客户端(绕过 RLS
const supabaseAdmin = createClient(
Deno.env.get('SUPABASE_URL')!,
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!,
);
// 检查单个计划的数据一致性
const checkPlanConsistency = async (pid: string) => {
// 获取计划信息
const { data: plan } = await supabaseAdmin
.from('production_plans')
.select('id, plan_code, completed_quantity, target_quantity')
.eq('id', pid)
.maybeSingle();
if (!plan) return null;
// 计算入库记录总和
const { data: records } = await supabaseAdmin
.from('inventory_records')
.select('quantity')
.eq('plan_id', pid);
const inventoryTotal = (records || []).reduce((sum, r) => sum + (r.quantity || 0), 0);
const completedQuantity = plan.completed_quantity || 0;
const diff = inventoryTotal - completedQuantity;
return {
planId: pid,
planCode: plan.plan_code,
completedQuantity,
inventoryTotal,
diff,
isConsistent: diff === 0,
};
};
// 检查所有计划的数据一致性
const checkAllPlans = async () => {
const { data: plans } = await supabaseAdmin
.from('production_plans')
.select('id');
const results = [];
for (const plan of (plans || [])) {
const result = await checkPlanConsistency(plan.id);
if (result && !result.isConsistent) {
results.push(result);
}
}
return results;
};
// 修复不一致的数据
const fixInconsistency = async (pid: string) => {
const check = await checkPlanConsistency(pid);
if (!check || check.isConsistent) {
return { fixed: false, message: '数据已一致,无需修复' };
}
// 以 inventory_records 为准修复 completed_quantity
const { data: records } = await supabaseAdmin
.from('inventory_records')
.select('quantity')
.eq('plan_id', pid);
const inventoryTotal = (records || []).reduce((sum, r) => sum + (r.quantity || 0), 0);
const { error } = await supabaseAdmin
.from('production_plans')
.update({ completed_quantity: inventoryTotal })
.eq('id', pid);
if (error) {
return { fixed: false, error: error.message };
}
return {
fixed: true,
planId: pid,
oldValue: check.completedQuantity,
newValue: inventoryTotal,
diff: check.diff,
};
};
let result;
switch (action) {
case 'check':
if (!planId) {
return new Response(
JSON.stringify({ error: 'check 操作需要提供 planId' }),
{ status: 400, headers: corsHeaders }
);
}
result = await checkPlanConsistency(planId);
break;
case 'check-all':
result = await checkAllPlans();
break;
case 'fix':
if (!planId) {
return new Response(
JSON.stringify({ error: 'fix 操作需要提供 planId' }),
{ status: 400, headers: corsHeaders }
);
}
result = await fixInconsistency(planId);
break;
case 'fix-all':
const inconsistentPlans = await checkAllPlans();
const fixResults = [];
for (const plan of inconsistentPlans) {
const fixResult = await fixInconsistency(plan.planId);
fixResults.push(fixResult);
}
result = {
totalChecked: inconsistentPlans.length,
fixed: fixResults.filter(r => r.fixed).length,
details: fixResults,
};
break;
default:
return new Response(
JSON.stringify({ error: '无效的操作类型,支持: check, check-all, fix, fix-all' }),
{ status: 400, headers: corsHeaders }
);
}
return new Response(
JSON.stringify({ success: true, data: result }),
{ headers: corsHeaders }
);
} catch (error) {
const message = error instanceof Error ? error.message : 'Unknown error';
return new Response(
JSON.stringify({ error: '服务器错误: ' + message }),
{ status: 500, headers: corsHeaders }
);
}
});

View File

@ -0,0 +1,148 @@
// 坯布入库事务处理 Edge Function
// 确保 completed_quantity 和 inventory_records 数据一致性
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
Deno.serve(async (req) => {
// CORS 预检
if (req.method === 'OPTIONS') {
return new Response('ok', {
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, OPTIONS',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
},
});
}
const corsHeaders = {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
};
try {
const body = await req.json();
const {
planId,
quantity,
rolls,
warehouseId,
warehouseLocation,
operatorId,
pricePerMeter,
} = body;
// 参数验证
if (!planId || !quantity || quantity <= 0) {
return new Response(
JSON.stringify({ error: '缺少必要参数或数量无效' }),
{ status: 400, headers: corsHeaders }
);
}
// 获取认证信息
const authHeader = req.headers.get('Authorization') || '';
// 创建管理员客户端(绕过 RLS
const supabaseAdmin = createClient(
Deno.env.get('SUPABASE_URL')!,
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!,
);
// 开始事务处理
// 1. 获取当前计划信息
const { data: plan, error: planError } = await supabaseAdmin
.from('production_plans')
.select('completed_quantity, target_quantity, purchaser_id')
.eq('id', planId)
.maybeSingle();
if (planError || !plan) {
return new Response(
JSON.stringify({ error: '获取计划信息失败: ' + (planError?.message || '计划不存在') }),
{ status: 404, headers: corsHeaders }
);
}
// 2. 计算新的已完成数量
const newCompletedQuantity = (plan.completed_quantity || 0) + quantity;
// 3. 检查是否超过目标数量
if (newCompletedQuantity > plan.target_quantity) {
return new Response(
JSON.stringify({ error: `入库数量超过剩余数量 (${plan.target_quantity - (plan.completed_quantity || 0)}米)` }),
{ status: 400, headers: corsHeaders }
);
}
const now = new Date().toISOString();
// 4. 更新计划的 completed_quantity
const { error: updateError } = await supabaseAdmin
.from('production_plans')
.update({ completed_quantity: newCompletedQuantity })
.eq('id', planId);
if (updateError) {
return new Response(
JSON.stringify({ error: '更新计划数量失败: ' + updateError.message }),
{ status: 500, headers: corsHeaders }
);
}
// 5. 创建入库记录
const insertData: any = {
plan_id: planId,
quantity: quantity,
rolls: rolls || 0,
warehouse_location: warehouseLocation || '',
operator_id: operatorId,
price_per_meter: pricePerMeter || 0,
created_at: now,
};
if (warehouseId) {
insertData.warehouse_id = warehouseId;
}
const { data: inventoryRecord, error: insertError } = await supabaseAdmin
.from('inventory_records')
.insert(insertData)
.select()
.single();
if (insertError) {
// 如果入库记录创建失败,需要回滚 completed_quantity
// 注意:这里简化处理,实际生产环境应使用数据库事务
await supabaseAdmin
.from('production_plans')
.update({ completed_quantity: plan.completed_quantity })
.eq('id', planId);
return new Response(
JSON.stringify({ error: '创建入库记录失败: ' + insertError.message }),
{ status: 500, headers: corsHeaders }
);
}
// 6. 返回成功结果
return new Response(
JSON.stringify({
success: true,
data: {
inventoryRecord,
completedQuantity: newCompletedQuantity,
progress: Math.round((newCompletedQuantity / plan.target_quantity) * 100),
},
}),
{ headers: corsHeaders }
);
} catch (error) {
const message = error instanceof Error ? error.message : 'Unknown error';
return new Response(
JSON.stringify({ error: '服务器错误: ' + message }),
{ status: 500, headers: corsHeaders }
);
}
});

56
index.html Normal file
View File

@ -0,0 +1,56 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>织机 - 以AI为梭织天地经纬</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* 内联样式确保主题色立即生效,避免闪烁 */
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
html.light, html.light body {
background-color: #ffffff !important;
color: #000000;
}
html.dark, html.dark body {
background-color: #1a1a1a !important;
color: #ffffff;
}
</style>
<script>
// 在 React 加载前立即设置主题,避免闪烁
(function() {
const isInIframe = window.self !== window.top;
function applyThemeToDOM(theme) {
document.documentElement.classList.remove('light', 'dark');
document.documentElement.classList.add(theme);
document.documentElement.setAttribute('data-theme', theme);
}
if (isInIframe) {
// 监听父窗口主动推送的主题消息
window.addEventListener('message', function(event) {
if (event.data && typeof event.data.theme === 'string') {
const theme = event.data.theme;
if (theme === 'light' || theme === 'dark') {
applyThemeToDOM(theme);
}
}
});
} else {
// 非 iframe 环境,使用默认 light 主题
applyThemeToDOM('light');
}
})();
</script>
</head>
<body>
<div id="root"></div>
</body>
</html>

34
jest.config.js Normal file
View File

@ -0,0 +1,34 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'jsdom',
roots: ['<rootDir>/src'],
testMatch: ['**/__tests__/**/*.test.ts', '**/__tests__/**/*.test.tsx'],
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'],
setupFilesAfterEnv: ['<rootDir>/src/__tests__/setup.ts'],
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
},
collectCoverageFrom: [
'src/**/*.{ts,tsx}',
'!src/**/*.d.ts',
'!src/__tests__/**',
'!src/index.tsx',
'!src/App.tsx',
],
coverageThreshold: {
global: {
branches: 30,
functions: 30,
lines: 30,
statements: 30,
},
},
transform: {
'^.+\\.tsx?$': ['ts-jest', {
tsconfig: {
jsx: 'react-jsx',
esModuleInterop: true,
},
}],
},
};

View File

@ -0,0 +1,46 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 自定义枚举类型
CREATE TYPE public.app_role AS ENUM ('purchaser', 'textile', 'washing');
CREATE TYPE public.factory_type AS ENUM ('textile', 'washing');
CREATE TYPE public.plan_status AS ENUM ('pending', 'producing', 'completed');
CREATE TYPE public.step_type AS ENUM ('confirm', 'yarn_purchase', 'dyeing', 'machine_start', 'fabric_warehouse');
CREATE TYPE public.step_status AS ENUM ('pending', 'active', 'completed');
CREATE TYPE public.warehouse_type AS ENUM ('raw_fabric', 'fabric', 'finished', 'yarn');
CREATE TYPE public.payment_status AS ENUM ('pending', 'completed');
-- 公司表
CREATE TABLE public.companies (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
role public.app_role NOT NULL,
address TEXT,
contact_phone TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- 用户配置表
CREATE TABLE public.profiles (
id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
username TEXT UNIQUE NOT NULL,
phone TEXT,
company_id UUID REFERENCES public.companies(id) ON DELETE SET NULL,
is_master BOOLEAN NOT NULL DEFAULT true,
master_id UUID REFERENCES auth.users(id) ON DELETE SET NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- 公司成员表
CREATE TABLE public.company_members (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
company_id UUID NOT NULL REFERENCES public.companies(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
role TEXT NOT NULL DEFAULT 'member',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(company_id, user_id)
);

View File

@ -0,0 +1,48 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 生产计划表
CREATE TABLE public.production_plans (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
plan_code TEXT UNIQUE NOT NULL,
product_name TEXT NOT NULL,
color TEXT NOT NULL,
fabric_code TEXT NOT NULL,
color_code TEXT NOT NULL DEFAULT '01',
remark TEXT,
purchaser_id UUID NOT NULL REFERENCES public.companies(id) ON DELETE CASCADE,
target_quantity INTEGER NOT NULL DEFAULT 0,
completed_quantity INTEGER NOT NULL DEFAULT 0,
yarn_usage_per_meter DECIMAL DEFAULT 0,
production_price DECIMAL DEFAULT 0,
status public.plan_status NOT NULL DEFAULT 'pending',
start_time TIMESTAMPTZ,
created_by UUID REFERENCES auth.users(id) ON DELETE SET NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- 计划与工厂关联表
CREATE TABLE public.plan_factories (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
plan_id UUID NOT NULL REFERENCES public.production_plans(id) ON DELETE CASCADE,
factory_id UUID NOT NULL REFERENCES public.companies(id) ON DELETE CASCADE,
factory_type public.factory_type NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(plan_id, factory_id)
);
-- 纱线配比表
CREATE TABLE public.yarn_ratios (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
plan_id UUID NOT NULL REFERENCES public.production_plans(id) ON DELETE CASCADE,
yarn_name TEXT NOT NULL,
ratio DECIMAL NOT NULL DEFAULT 1,
amount_per_meter DECIMAL NOT NULL DEFAULT 0,
total_amount DECIMAL NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

View File

@ -0,0 +1,40 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 仓库表
CREATE TABLE public.warehouses (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
company_id UUID NOT NULL REFERENCES public.companies(id) ON DELETE CASCADE,
name TEXT NOT NULL,
type public.warehouse_type NOT NULL,
location TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- 入库记录表
CREATE TABLE public.inventory_records (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
plan_id UUID NOT NULL REFERENCES public.production_plans(id) ON DELETE CASCADE,
warehouse_id UUID NOT NULL REFERENCES public.warehouses(id) ON DELETE CASCADE,
quantity DECIMAL NOT NULL DEFAULT 0,
warehouse_location TEXT,
operator_id UUID REFERENCES auth.users(id) ON DELETE SET NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- 纱线库存表
CREATE TABLE public.yarn_stock (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
company_id UUID NOT NULL REFERENCES public.companies(id) ON DELETE CASCADE,
warehouse_id UUID REFERENCES public.warehouses(id) ON DELETE SET NULL,
name TEXT NOT NULL,
spec TEXT,
quantity DECIMAL NOT NULL DEFAULT 0,
min_stock DECIMAL NOT NULL DEFAULT 0,
unit TEXT NOT NULL DEFAULT 'kg',
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

View File

@ -0,0 +1,32 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 流程节点表
CREATE TABLE public.plan_process_steps (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
plan_id UUID NOT NULL REFERENCES public.production_plans(id) ON DELETE CASCADE,
step_type public.step_type NOT NULL,
status public.step_status NOT NULL DEFAULT 'pending',
timestamp TIMESTAMPTZ,
operator_id UUID REFERENCES auth.users(id) ON DELETE SET NULL,
notes TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- 结款记录表
CREATE TABLE public.payments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
plan_id UUID NOT NULL REFERENCES public.production_plans(id) ON DELETE CASCADE,
from_company_id UUID NOT NULL REFERENCES public.companies(id) ON DELETE CASCADE,
to_company_id UUID NOT NULL REFERENCES public.companies(id) ON DELETE CASCADE,
amount DECIMAL NOT NULL DEFAULT 0,
quantity DECIMAL NOT NULL DEFAULT 0,
price_per_meter DECIMAL NOT NULL DEFAULT 0,
status public.payment_status NOT NULL DEFAULT 'pending',
paid_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

View File

@ -0,0 +1,73 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 启用所有表的 RLS
ALTER TABLE public.companies ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.company_members ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.production_plans ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.plan_factories ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.yarn_ratios ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.warehouses ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.inventory_records ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.yarn_stock ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.plan_process_steps ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.payments ENABLE ROW LEVEL SECURITY;
-- companies: 所有人可查看,登录用户可创建/修改自己公司的
CREATE POLICY anon_select_companies ON public.companies FOR SELECT USING (true);
CREATE POLICY anon_insert_companies ON public.companies FOR INSERT WITH CHECK (true);
CREATE POLICY anon_update_companies ON public.companies FOR UPDATE USING (true);
-- profiles: 登录用户可查看所有profile只能修改自己的
CREATE POLICY anon_select_profiles ON public.profiles FOR SELECT USING (true);
CREATE POLICY anon_insert_profiles ON public.profiles FOR INSERT WITH CHECK (true);
CREATE POLICY users_update_own_profile ON public.profiles FOR UPDATE USING (auth.uid() = id);
-- company_members: 所有人可查看和创建
CREATE POLICY anon_select_company_members ON public.company_members FOR SELECT USING (true);
CREATE POLICY anon_insert_company_members ON public.company_members FOR INSERT WITH CHECK (true);
-- production_plans: 所有人可查看,登录用户可创建/修改
CREATE POLICY anon_select_plans ON public.production_plans FOR SELECT USING (true);
CREATE POLICY anon_insert_plans ON public.production_plans FOR INSERT WITH CHECK (true);
CREATE POLICY anon_update_plans ON public.production_plans FOR UPDATE USING (true);
CREATE POLICY anon_delete_plans ON public.production_plans FOR DELETE USING (true);
-- plan_factories: 所有人可查看和操作
CREATE POLICY anon_select_plan_factories ON public.plan_factories FOR SELECT USING (true);
CREATE POLICY anon_insert_plan_factories ON public.plan_factories FOR INSERT WITH CHECK (true);
CREATE POLICY anon_delete_plan_factories ON public.plan_factories FOR DELETE USING (true);
-- yarn_ratios: 所有人可查看和操作
CREATE POLICY anon_select_yarn_ratios ON public.yarn_ratios FOR SELECT USING (true);
CREATE POLICY anon_insert_yarn_ratios ON public.yarn_ratios FOR INSERT WITH CHECK (true);
CREATE POLICY anon_delete_yarn_ratios ON public.yarn_ratios FOR DELETE USING (true);
-- warehouses: 所有人可查看和操作
CREATE POLICY anon_select_warehouses ON public.warehouses FOR SELECT USING (true);
CREATE POLICY anon_insert_warehouses ON public.warehouses FOR INSERT WITH CHECK (true);
CREATE POLICY anon_update_warehouses ON public.warehouses FOR UPDATE USING (true);
-- inventory_records: 所有人可查看和操作
CREATE POLICY anon_select_inventory ON public.inventory_records FOR SELECT USING (true);
CREATE POLICY anon_insert_inventory ON public.inventory_records FOR INSERT WITH CHECK (true);
-- yarn_stock: 所有人可查看和操作
CREATE POLICY anon_select_yarn_stock ON public.yarn_stock FOR SELECT USING (true);
CREATE POLICY anon_insert_yarn_stock ON public.yarn_stock FOR INSERT WITH CHECK (true);
CREATE POLICY anon_update_yarn_stock ON public.yarn_stock FOR UPDATE USING (true);
-- plan_process_steps: 所有人可查看和操作
CREATE POLICY anon_select_process_steps ON public.plan_process_steps FOR SELECT USING (true);
CREATE POLICY anon_insert_process_steps ON public.plan_process_steps FOR INSERT WITH CHECK (true);
CREATE POLICY anon_update_process_steps ON public.plan_process_steps FOR UPDATE USING (true);
-- payments: 所有人可查看和操作
CREATE POLICY anon_select_payments ON public.payments FOR SELECT USING (true);
CREATE POLICY anon_insert_payments ON public.payments FOR INSERT WITH CHECK (true);
CREATE POLICY anon_update_payments ON public.payments FOR UPDATE USING (true);

View File

@ -0,0 +1,66 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
INSERT INTO auth.users (
instance_id, id, aud, role, email,
encrypted_password, email_confirmed_at,
created_at, updated_at,
confirmation_token, recovery_token,
email_change_token_new, email_change,
raw_app_meta_data, raw_user_meta_data,
is_super_admin
) VALUES (
'00000000-0000-0000-0000-000000000000',
'a0000001-0000-0000-0000-000000000001'::uuid, 'authenticated', 'authenticated',
'purchaser@meoo.local',
crypt('123456', gen_salt('bf')),
NOW(), NOW(), NOW(),
'', '', '', '',
'{"provider":"email","providers":["email"]}'::jsonb,
'{"username":"purchaser"}'::jsonb,
false
);
INSERT INTO auth.users (
instance_id, id, aud, role, email,
encrypted_password, email_confirmed_at,
created_at, updated_at,
confirmation_token, recovery_token,
email_change_token_new, email_change,
raw_app_meta_data, raw_user_meta_data,
is_super_admin
) VALUES (
'00000000-0000-0000-0000-000000000000',
'a0000002-0000-0000-0000-000000000002'::uuid, 'authenticated', 'authenticated',
'textile@meoo.local',
crypt('123456', gen_salt('bf')),
NOW(), NOW(), NOW(),
'', '', '', '',
'{"provider":"email","providers":["email"]}'::jsonb,
'{"username":"textile"}'::jsonb,
false
);
INSERT INTO auth.users (
instance_id, id, aud, role, email,
encrypted_password, email_confirmed_at,
created_at, updated_at,
confirmation_token, recovery_token,
email_change_token_new, email_change,
raw_app_meta_data, raw_user_meta_data,
is_super_admin
) VALUES (
'00000000-0000-0000-0000-000000000000',
'a0000003-0000-0000-0000-000000000003'::uuid, 'authenticated', 'authenticated',
'washing@meoo.local',
crypt('123456', gen_salt('bf')),
NOW(), NOW(), NOW(),
'', '', '', '',
'{"provider":"email","providers":["email"]}'::jsonb,
'{"username":"washing"}'::jsonb,
false
);

View File

@ -0,0 +1,37 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 创建公司
INSERT INTO public.companies (id, name, role, address, contact_phone) VALUES
('11111111-1111-1111-1111-111111111101', '示例布行', 'purchaser', '浙江省杭州市', '13800138000'),
('11111111-1111-1111-1111-111111111102', '示例纺织厂', 'textile', '浙江省绍兴市', '13800138001'),
('11111111-1111-1111-1111-111111111103', '示例水洗厂', 'washing', '广东省广州市', '13800138002');
-- 创建 profiles
INSERT INTO public.profiles (id, username, phone, company_id, is_master) VALUES
('a0000001-0000-0000-0000-000000000001', 'purchaser', '13800138000', '11111111-1111-1111-1111-111111111101', true),
('a0000002-0000-0000-0000-000000000002', 'textile', '13800138001', '11111111-1111-1111-1111-111111111102', true),
('a0000003-0000-0000-0000-000000000003', 'washing', '13800138002', '11111111-1111-1111-1111-111111111103', true);
-- 创建公司成员
INSERT INTO public.company_members (company_id, user_id, role) VALUES
('11111111-1111-1111-1111-111111111101', 'a0000001-0000-0000-0000-000000000001', 'master'),
('11111111-1111-1111-1111-111111111102', 'a0000002-0000-0000-0000-000000000002', 'master'),
('11111111-1111-1111-1111-111111111103', 'a0000003-0000-0000-0000-000000000003', 'master');
-- 创建仓库
INSERT INTO public.warehouses (id, company_id, name, type, location) VALUES
('22222222-2222-2222-2222-222222222201', '11111111-1111-1111-1111-111111111101', '原坯布仓库', 'raw_fabric', 'A区-01'),
('22222222-2222-2222-2222-222222222202', '11111111-1111-1111-1111-111111111101', '坯布仓库', 'fabric', 'B区-01'),
('22222222-2222-2222-2222-222222222203', '11111111-1111-1111-1111-111111111101', '成品仓库', 'finished', 'C区-01'),
('22222222-2222-2222-2222-222222222204', '11111111-1111-1111-1111-111111111102', '原料纱仓库', 'yarn', '绍兴厂区');
-- 创建纱线库存
INSERT INTO public.yarn_stock (company_id, warehouse_id, name, spec, quantity, min_stock, unit) VALUES
('11111111-1111-1111-1111-111111111102', '22222222-2222-2222-2222-222222222204', '棉纱32S', '32支纯棉', 500, 100, 'kg'),
('11111111-1111-1111-1111-111111111102', '22222222-2222-2222-2222-222222222204', '涤纶纱', '75D/36F', 30, 50, 'kg'),
('11111111-1111-1111-1111-111111111102', '22222222-2222-2222-2222-222222222204', '氨纶', '40D', 200, 80, 'kg');

View File

@ -0,0 +1,37 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 创建示例生产计划
INSERT INTO public.production_plans (id, plan_code, product_name, color, fabric_code, color_code, remark, purchaser_id, target_quantity, completed_quantity, yarn_usage_per_meter, production_price, status, start_time, created_by) VALUES
('33333333-3333-3333-3333-333333333301', 'PLAN-2026-001', '水洗棉花糖', '白色', 'SX', '01', '60*40', '11111111-1111-1111-1111-111111111101', 10000, 6500, 100, 10, 'producing', '2026-01-15T00:00:00Z', 'a0000001-0000-0000-0000-000000000001'),
('33333333-3333-3333-3333-333333333302', 'PLAN-2026-002', '纯棉汗布', '黑色', 'CM', '02', '60双股', '11111111-1111-1111-1111-111111111101', 8000, 0, 120, 12, 'pending', NULL, 'a0000001-0000-0000-0000-000000000001'),
('33333333-3333-3333-3333-333333333303', 'PLAN-2026-003', '磨毛布', '灰色', 'MM', '03', '40*40', '11111111-1111-1111-1111-111111111101', 5000, 5000, 80, 8, 'completed', '2026-01-01T00:00:00Z', 'a0000001-0000-0000-0000-000000000001');
-- 创建计划与工厂关联
INSERT INTO public.plan_factories (plan_id, factory_id, factory_type) VALUES
('33333333-3333-3333-3333-333333333301', '11111111-1111-1111-1111-111111111102', 'textile'),
('33333333-3333-3333-3333-333333333302', '11111111-1111-1111-1111-111111111102', 'textile'),
('33333333-3333-3333-3333-333333333303', '11111111-1111-1111-1111-111111111102', 'textile');
-- 创建纱线配比
INSERT INTO public.yarn_ratios (plan_id, yarn_name, ratio, amount_per_meter, total_amount) VALUES
('33333333-3333-3333-3333-333333333301', '棉纱32S', 1, 10, 100000),
('33333333-3333-3333-3333-333333333301', '涤纶纱', 1, 10, 100000),
('33333333-3333-3333-3333-333333333301', '氨纶', 8, 80, 800000);
-- 创建流程节点
INSERT INTO public.plan_process_steps (plan_id, step_type, status, timestamp, operator_id) VALUES
('33333333-3333-3333-3333-333333333301', 'confirm', 'completed', '2026-01-15T09:30:00Z', 'a0000001-0000-0000-0000-000000000001'),
('33333333-3333-3333-3333-333333333301', 'yarn_purchase', 'completed', '2026-01-16T14:20:00Z', 'a0000002-0000-0000-0000-000000000002'),
('33333333-3333-3333-3333-333333333301', 'dyeing', 'completed', '2026-01-18T10:00:00Z', 'a0000002-0000-0000-0000-000000000002'),
('33333333-3333-3333-3333-333333333301', 'machine_start', 'active', '2026-01-20T08:00:00Z', 'a0000002-0000-0000-0000-000000000002'),
('33333333-3333-3333-3333-333333333301', 'fabric_warehouse', 'pending', NULL, NULL);
-- 创建结款记录
INSERT INTO public.payments (plan_id, from_company_id, to_company_id, amount, quantity, price_per_meter, status) VALUES
('33333333-3333-3333-3333-333333333301', '11111111-1111-1111-1111-111111111101', '11111111-1111-1111-1111-111111111102', 65000, 6500, 10, 'pending'),
('33333333-3333-3333-3333-333333333303', '11111111-1111-1111-1111-111111111101', '11111111-1111-1111-1111-111111111102', 50000, 5000, 10, 'pending');

View File

@ -0,0 +1,14 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
ALTER TABLE product_inventory_records ADD COLUMN company_id UUID REFERENCES companies(id) ON DELETE CASCADE;
-- 更新RLS策略
CREATE POLICY company_select_product_inventory_records ON product_inventory_records FOR SELECT USING (true);
CREATE POLICY company_insert_product_inventory_records ON product_inventory_records FOR INSERT WITH CHECK (true);
CREATE POLICY company_update_product_inventory_records ON product_inventory_records FOR UPDATE USING (true);
CREATE POLICY company_delete_product_inventory_records ON product_inventory_records FOR DELETE USING (true);

View File

@ -0,0 +1,24 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 创建产品纱线配比表
CREATE TABLE IF NOT EXISTS product_yarn_ratios (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
product_id UUID NOT NULL REFERENCES products(id) ON DELETE CASCADE,
yarn_name TEXT NOT NULL,
ratio DECIMAL(5,2) NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- 启用RLS
ALTER TABLE product_yarn_ratios ENABLE ROW LEVEL SECURITY;
-- RLS策略
CREATE POLICY company_select_product_yarn_ratios ON product_yarn_ratios FOR SELECT USING (true);
CREATE POLICY company_insert_product_yarn_ratios ON product_yarn_ratios FOR INSERT WITH CHECK (true);
CREATE POLICY company_update_product_yarn_ratios ON product_yarn_ratios FOR UPDATE USING (true);
CREATE POLICY company_delete_product_yarn_ratios ON product_yarn_ratios FOR DELETE USING (true);

View File

@ -0,0 +1,6 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
ALTER TABLE products ADD COLUMN IF NOT EXISTS production_price DECIMAL(10,2) DEFAULT 0;

View File

@ -0,0 +1,6 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
ALTER TABLE inventory_records ADD COLUMN IF NOT EXISTS rolls INTEGER DEFAULT 0;

View File

@ -0,0 +1,40 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 删除现有宽松的 RLS 策略
DROP POLICY IF EXISTS anon_select_companies ON public.companies;
DROP POLICY IF EXISTS anon_insert_companies ON public.companies;
DROP POLICY IF EXISTS anon_update_companies ON public.companies;
DROP POLICY IF EXISTS anon_select_profiles ON public.profiles;
DROP POLICY IF EXISTS anon_insert_profiles ON public.profiles;
DROP POLICY IF EXISTS users_update_own_profile ON public.profiles;
DROP POLICY IF EXISTS anon_select_company_members ON public.company_members;
DROP POLICY IF EXISTS anon_insert_company_members ON public.company_members;
DROP POLICY IF EXISTS anon_select_plans ON public.production_plans;
DROP POLICY IF EXISTS anon_insert_plans ON public.production_plans;
DROP POLICY IF EXISTS anon_update_plans ON public.production_plans;
DROP POLICY IF EXISTS anon_delete_plans ON public.production_plans;
DROP POLICY IF EXISTS anon_select_plan_factories ON public.plan_factories;
DROP POLICY IF EXISTS anon_insert_plan_factories ON public.plan_factories;
DROP POLICY IF EXISTS anon_delete_plan_factories ON public.plan_factories;
DROP POLICY IF EXISTS anon_select_yarn_ratios ON public.yarn_ratios;
DROP POLICY IF EXISTS anon_insert_yarn_ratios ON public.yarn_ratios;
DROP POLICY IF EXISTS anon_delete_yarn_ratios ON public.yarn_ratios;
DROP POLICY IF EXISTS anon_select_warehouses ON public.warehouses;
DROP POLICY IF EXISTS anon_insert_warehouses ON public.warehouses;
DROP POLICY IF EXISTS anon_update_warehouses ON public.warehouses;
DROP POLICY IF EXISTS anon_select_inventory ON public.inventory_records;
DROP POLICY IF EXISTS anon_insert_inventory ON public.inventory_records;
DROP POLICY IF EXISTS anon_select_yarn_stock ON public.yarn_stock;
DROP POLICY IF EXISTS anon_insert_yarn_stock ON public.yarn_stock;
DROP POLICY IF EXISTS anon_update_yarn_stock ON public.yarn_stock;
DROP POLICY IF EXISTS anon_select_process_steps ON public.plan_process_steps;
DROP POLICY IF EXISTS anon_insert_process_steps ON public.plan_process_steps;
DROP POLICY IF EXISTS anon_update_process_steps ON public.plan_process_steps;
DROP POLICY IF EXISTS anon_select_payments ON public.payments;
DROP POLICY IF EXISTS anon_insert_payments ON public.payments;
DROP POLICY IF EXISTS anon_update_payments ON public.payments;

View File

@ -0,0 +1,23 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 创建辅助函数获取当前用户的公司ID
CREATE OR REPLACE FUNCTION public.get_current_user_company_id()
RETURNS UUID
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
company_id UUID;
BEGIN
SELECT p.company_id INTO company_id
FROM public.profiles p
WHERE p.id = auth.uid();
RETURN company_id;
END;
$$;

View File

@ -0,0 +1,32 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 创建辅助函数获取用户主账号公司ID用于子账号
CREATE OR REPLACE FUNCTION public.get_user_master_company_id()
RETURNS UUID
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
user_company_id UUID;
user_master_id UUID;
BEGIN
SELECT company_id, master_id INTO user_company_id, user_master_id
FROM public.profiles
WHERE id = auth.uid();
-- 如果是子账号返回主账号的公司ID
IF user_master_id IS NOT NULL THEN
SELECT company_id INTO user_company_id
FROM public.profiles
WHERE id = user_master_id;
END IF;
RETURN user_company_id;
END;
$$;

View File

@ -0,0 +1,22 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- companies 表 RLS 策略
-- 用户只能查看、修改自己公司的数据
CREATE POLICY users_select_own_company ON public.companies
FOR SELECT USING (
id = public.get_user_master_company_id()
);
CREATE POLICY users_update_own_company ON public.companies
FOR UPDATE USING (
id = public.get_user_master_company_id()
);
-- 允许创建公司(注册时需要)
CREATE POLICY users_insert_company ON public.companies
FOR INSERT WITH CHECK (true);

View File

@ -0,0 +1,24 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- profiles 表 RLS 策略
-- 用户可以查看自己公司的所有成员资料
CREATE POLICY users_select_company_profiles ON public.profiles
FOR SELECT USING (
company_id = public.get_user_master_company_id()
OR id = auth.uid()
);
-- 用户可以修改自己的资料
CREATE POLICY users_update_own_profile ON public.profiles
FOR UPDATE USING (
id = auth.uid()
);
-- 允许创建 profile注册时需要
CREATE POLICY users_insert_profile ON public.profiles
FOR INSERT WITH CHECK (true);

View File

@ -0,0 +1,31 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- production_plans 表 RLS 策略
-- 采购商可以查看、修改、删除自己创建的计划
CREATE POLICY purchaser_select_plans ON public.production_plans
FOR SELECT USING (
purchaser_id = public.get_user_master_company_id()
);
CREATE POLICY purchaser_insert_plans ON public.production_plans
FOR INSERT WITH CHECK (
purchaser_id = public.get_user_master_company_id()
);
CREATE POLICY purchaser_update_plans ON public.production_plans
FOR UPDATE USING (
purchaser_id = public.get_user_master_company_id()
);
CREATE POLICY purchaser_delete_plans ON public.production_plans
FOR DELETE USING (
purchaser_id = public.get_user_master_company_id()
);
-- 工厂可以查看关联的计划(通过 plan_factories 关联)
-- 这个策略需要配合 plan_factories 的查询

View File

@ -0,0 +1,39 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- plan_factories 表 RLS 策略
-- 工厂可以查看和管理关联到自己的计划
CREATE POLICY factory_select_plan_factories ON public.plan_factories
FOR SELECT USING (
factory_id = public.get_user_master_company_id()
);
-- 采购商可以查看自己计划的工厂关联
CREATE POLICY purchaser_select_plan_factories ON public.plan_factories
FOR SELECT USING (
EXISTS (
SELECT 1 FROM public.production_plans
WHERE id = plan_id AND purchaser_id = public.get_user_master_company_id()
)
);
-- 采购商可以创建和删除工厂关联
CREATE POLICY purchaser_insert_plan_factories ON public.plan_factories
FOR INSERT WITH CHECK (
EXISTS (
SELECT 1 FROM public.production_plans
WHERE id = plan_id AND purchaser_id = public.get_user_master_company_id()
)
);
CREATE POLICY purchaser_delete_plan_factories ON public.plan_factories
FOR DELETE USING (
EXISTS (
SELECT 1 FROM public.production_plans
WHERE id = plan_id AND purchaser_id = public.get_user_master_company_id()
)
);

View File

@ -0,0 +1,45 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- warehouses 表 RLS 策略
CREATE POLICY users_select_company_warehouses ON public.warehouses
FOR SELECT USING (
company_id = public.get_user_master_company_id()
);
CREATE POLICY users_insert_company_warehouses ON public.warehouses
FOR INSERT WITH CHECK (
company_id = public.get_user_master_company_id()
);
CREATE POLICY users_update_company_warehouses ON public.warehouses
FOR UPDATE USING (
company_id = public.get_user_master_company_id()
);
CREATE POLICY users_delete_company_warehouses ON public.warehouses
FOR DELETE USING (
company_id = public.get_user_master_company_id()
);
-- inventory_records 表 RLS 策略
-- 通过 warehouse 关联到公司
CREATE POLICY users_select_company_inventory ON public.inventory_records
FOR SELECT USING (
EXISTS (
SELECT 1 FROM public.warehouses
WHERE id = warehouse_id AND company_id = public.get_user_master_company_id()
)
);
CREATE POLICY users_insert_company_inventory ON public.inventory_records
FOR INSERT WITH CHECK (
EXISTS (
SELECT 1 FROM public.warehouses
WHERE id = warehouse_id AND company_id = public.get_user_master_company_id()
)
);

View File

@ -0,0 +1,53 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- yarn_stock 表 RLS 策略
CREATE POLICY users_select_company_yarn_stock ON public.yarn_stock
FOR SELECT USING (
company_id = public.get_user_master_company_id()
);
CREATE POLICY users_insert_company_yarn_stock ON public.yarn_stock
FOR INSERT WITH CHECK (
company_id = public.get_user_master_company_id()
);
CREATE POLICY users_update_company_yarn_stock ON public.yarn_stock
FOR UPDATE USING (
company_id = public.get_user_master_company_id()
);
CREATE POLICY users_delete_company_yarn_stock ON public.yarn_stock
FOR DELETE USING (
company_id = public.get_user_master_company_id()
);
-- yarn_ratios 表 RLS 策略
-- 通过 plan 关联到采购商
CREATE POLICY users_select_yarn_ratios ON public.yarn_ratios
FOR SELECT USING (
EXISTS (
SELECT 1 FROM public.production_plans
WHERE id = plan_id AND purchaser_id = public.get_user_master_company_id()
)
);
CREATE POLICY users_insert_yarn_ratios ON public.yarn_ratios
FOR INSERT WITH CHECK (
EXISTS (
SELECT 1 FROM public.production_plans
WHERE id = plan_id AND purchaser_id = public.get_user_master_company_id()
)
);
CREATE POLICY users_delete_yarn_ratios ON public.yarn_ratios
FOR DELETE USING (
EXISTS (
SELECT 1 FROM public.production_plans
WHERE id = plan_id AND purchaser_id = public.get_user_master_company_id()
)
);

View File

@ -0,0 +1,77 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- payments 表 RLS 策略
-- 付款方或收款方可以查看相关结款记录
CREATE POLICY users_select_payments ON public.payments
FOR SELECT USING (
from_company_id = public.get_user_master_company_id()
OR to_company_id = public.get_user_master_company_id()
);
CREATE POLICY users_insert_payments ON public.payments
FOR INSERT WITH CHECK (
from_company_id = public.get_user_master_company_id()
OR to_company_id = public.get_user_master_company_id()
);
CREATE POLICY users_update_payments ON public.payments
FOR UPDATE USING (
from_company_id = public.get_user_master_company_id()
OR to_company_id = public.get_user_master_company_id()
);
-- plan_process_steps 表 RLS 策略
-- 关联计划的采购商或工厂可以查看流程步骤
CREATE POLICY users_select_process_steps ON public.plan_process_steps
FOR SELECT USING (
EXISTS (
SELECT 1 FROM public.production_plans p
JOIN public.plan_factories pf ON p.id = pf.plan_id
WHERE p.id = plan_id
AND (p.purchaser_id = public.get_user_master_company_id()
OR pf.factory_id = public.get_user_master_company_id())
)
);
CREATE POLICY users_insert_process_steps ON public.plan_process_steps
FOR INSERT WITH CHECK (
EXISTS (
SELECT 1 FROM public.production_plans p
JOIN public.plan_factories pf ON p.id = pf.plan_id
WHERE p.id = plan_id
AND (p.purchaser_id = public.get_user_master_company_id()
OR pf.factory_id = public.get_user_master_company_id())
)
);
CREATE POLICY users_update_process_steps ON public.plan_process_steps
FOR UPDATE USING (
EXISTS (
SELECT 1 FROM public.production_plans p
JOIN public.plan_factories pf ON p.id = pf.plan_id
WHERE p.id = plan_id
AND (p.purchaser_id = public.get_user_master_company_id()
OR pf.factory_id = public.get_user_master_company_id())
)
);
-- company_members 表 RLS 策略
CREATE POLICY users_select_company_members ON public.company_members
FOR SELECT USING (
company_id = public.get_user_master_company_id()
);
CREATE POLICY users_insert_company_members ON public.company_members
FOR INSERT WITH CHECK (
company_id = public.get_user_master_company_id()
);
CREATE POLICY users_delete_company_members ON public.company_members
FOR DELETE USING (
company_id = public.get_user_master_company_id()
);

View File

@ -0,0 +1,28 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 删除 products 表上的旧宽松策略
DROP POLICY IF EXISTS anon_select_products ON public.products;
DROP POLICY IF EXISTS anon_insert_products ON public.products;
DROP POLICY IF EXISTS anon_update_products ON public.products;
DROP POLICY IF EXISTS anon_delete_products ON public.products;
-- 删除 product_inventory_records 表上的旧宽松策略
DROP POLICY IF EXISTS anon_select_product_inventory_records ON public.product_inventory_records;
DROP POLICY IF EXISTS anon_insert_product_inventory_records ON public.product_inventory_records;
DROP POLICY IF EXISTS anon_update_product_inventory_records ON public.product_inventory_records;
DROP POLICY IF EXISTS anon_delete_product_inventory_records ON public.product_inventory_records;
DROP POLICY IF EXISTS company_select_product_inventory_records ON public.product_inventory_records;
DROP POLICY IF EXISTS company_insert_product_inventory_records ON public.product_inventory_records;
DROP POLICY IF EXISTS company_update_product_inventory_records ON public.product_inventory_records;
DROP POLICY IF EXISTS company_delete_product_inventory_records ON public.product_inventory_records;
-- 删除 product_yarn_ratios 表上的旧宽松策略
DROP POLICY IF EXISTS company_select_product_yarn_ratios ON public.product_yarn_ratios;
DROP POLICY IF EXISTS company_insert_product_yarn_ratios ON public.product_yarn_ratios;
DROP POLICY IF EXISTS company_update_product_yarn_ratios ON public.product_yarn_ratios;
DROP POLICY IF EXISTS company_delete_product_yarn_ratios ON public.product_yarn_ratios;

View File

@ -0,0 +1,22 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 修复 profiles 策略中的 uid() 为 auth.uid()
DROP POLICY IF EXISTS users_select_company_profiles ON public.profiles;
DROP POLICY IF EXISTS users_update_own_profile ON public.profiles;
-- 重新创建正确的策略
CREATE POLICY users_select_company_profiles ON public.profiles
FOR SELECT USING (
company_id = public.get_user_master_company_id()
OR id = auth.uid()
);
CREATE POLICY users_update_own_profile ON public.profiles
FOR UPDATE USING (
id = auth.uid()
);

View File

@ -0,0 +1,12 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 为 inventory_records 表添加 company_id 字段
ALTER TABLE public.inventory_records ADD COLUMN IF NOT EXISTS company_id UUID REFERENCES public.companies(id) ON DELETE CASCADE;
-- 创建索引优化查询
CREATE INDEX IF NOT EXISTS idx_inventory_records_company_id ON public.inventory_records(company_id);

View File

@ -0,0 +1,12 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 为 yarn_ratios 表添加 company_id 字段
ALTER TABLE public.yarn_ratios ADD COLUMN IF NOT EXISTS company_id UUID REFERENCES public.companies(id) ON DELETE CASCADE;
-- 创建索引优化查询
CREATE INDEX IF NOT EXISTS idx_yarn_ratios_company_id ON public.yarn_ratios(company_id);

View File

@ -0,0 +1,12 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 为 plan_process_steps 表添加 company_id 字段
ALTER TABLE public.plan_process_steps ADD COLUMN IF NOT EXISTS company_id UUID REFERENCES public.companies(id) ON DELETE CASCADE;
-- 创建索引优化查询
CREATE INDEX IF NOT EXISTS idx_plan_process_steps_company_id ON public.plan_process_steps(company_id);

View File

@ -0,0 +1,31 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 删除旧的 RLS 策略
DROP POLICY IF EXISTS users_select_company_inventory ON public.inventory_records;
DROP POLICY IF EXISTS users_insert_company_inventory ON public.inventory_records;
-- 创建优化的 RLS 策略(直接使用 company_id
CREATE POLICY users_select_company_inventory ON public.inventory_records
FOR SELECT USING (
company_id = public.get_user_master_company_id()
);
CREATE POLICY users_insert_company_inventory ON public.inventory_records
FOR INSERT WITH CHECK (
company_id = public.get_user_master_company_id()
);
CREATE POLICY users_update_company_inventory ON public.inventory_records
FOR UPDATE USING (
company_id = public.get_user_master_company_id()
);
CREATE POLICY users_delete_company_inventory ON public.inventory_records
FOR DELETE USING (
company_id = public.get_user_master_company_id()
);

View File

@ -0,0 +1,32 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 删除旧的 RLS 策略
DROP POLICY IF EXISTS users_select_yarn_ratios ON public.yarn_ratios;
DROP POLICY IF EXISTS users_insert_yarn_ratios ON public.yarn_ratios;
DROP POLICY IF EXISTS users_delete_yarn_ratios ON public.yarn_ratios;
-- 创建优化的 RLS 策略(直接使用 company_id
CREATE POLICY users_select_yarn_ratios ON public.yarn_ratios
FOR SELECT USING (
company_id = public.get_user_master_company_id()
);
CREATE POLICY users_insert_yarn_ratios ON public.yarn_ratios
FOR INSERT WITH CHECK (
company_id = public.get_user_master_company_id()
);
CREATE POLICY users_update_yarn_ratios ON public.yarn_ratios
FOR UPDATE USING (
company_id = public.get_user_master_company_id()
);
CREATE POLICY users_delete_yarn_ratios ON public.yarn_ratios
FOR DELETE USING (
company_id = public.get_user_master_company_id()
);

View File

@ -0,0 +1,32 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 删除旧的 RLS 策略
DROP POLICY IF EXISTS users_select_process_steps ON public.plan_process_steps;
DROP POLICY IF EXISTS users_insert_process_steps ON public.plan_process_steps;
DROP POLICY IF EXISTS users_update_process_steps ON public.plan_process_steps;
-- 创建优化的 RLS 策略(直接使用 company_id
CREATE POLICY users_select_process_steps ON public.plan_process_steps
FOR SELECT USING (
company_id = public.get_user_master_company_id()
);
CREATE POLICY users_insert_process_steps ON public.plan_process_steps
FOR INSERT WITH CHECK (
company_id = public.get_user_master_company_id()
);
CREATE POLICY users_update_process_steps ON public.plan_process_steps
FOR UPDATE USING (
company_id = public.get_user_master_company_id()
);
CREATE POLICY users_delete_process_steps ON public.plan_process_steps
FOR DELETE USING (
company_id = public.get_user_master_company_id()
);

View File

@ -0,0 +1,27 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 更新 inventory_records 的 company_id通过 warehouse 关联)
UPDATE public.inventory_records ir
SET company_id = w.company_id
FROM public.warehouses w
WHERE ir.warehouse_id = w.id
AND ir.company_id IS NULL;
-- 更新 yarn_ratios 的 company_id通过 production_plans 关联)
UPDATE public.yarn_ratios yr
SET company_id = pp.purchaser_id
FROM public.production_plans pp
WHERE yr.plan_id = pp.id
AND yr.company_id IS NULL;
-- 更新 plan_process_steps 的 company_id通过 production_plans 关联)
UPDATE public.plan_process_steps pps
SET company_id = pp.purchaser_id
FROM public.production_plans pp
WHERE pps.plan_id = pp.id
AND pps.company_id IS NULL;

View File

@ -0,0 +1,37 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 为分享链接场景添加特殊的 RLS 策略
-- 允许工厂查看通过 plan_factories 关联的计划
-- production_plans工厂可以查看关联的计划
CREATE POLICY factory_select_plans_via_share ON public.production_plans
FOR SELECT USING (
EXISTS (
SELECT 1 FROM public.plan_factories
WHERE plan_id = production_plans.id
AND factory_id = public.get_user_master_company_id()
)
);
-- yarn_ratios工厂可以查看关联计划的纱线配比
CREATE POLICY factory_select_yarn_ratios_via_share ON public.yarn_ratios
FOR SELECT USING (
EXISTS (
SELECT 1 FROM public.plan_factories
WHERE plan_id = yarn_ratios.plan_id
AND factory_id = public.get_user_master_company_id()
)
);
-- companies允许查看所有公司用于显示采购商名称
-- 删除旧的限制策略,创建新的开放查询策略
DROP POLICY IF EXISTS users_select_own_company ON public.companies;
-- 允许所有登录用户查看所有公司信息(用于分享链接显示采购商名称)
CREATE POLICY users_select_companies ON public.companies
FOR SELECT USING (true);

View File

@ -0,0 +1,41 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 删除刚才创建的策略(有问题)
DROP POLICY IF EXISTS factory_select_plans_via_share ON public.production_plans;
DROP POLICY IF EXISTS factory_select_yarn_ratios_via_share ON public.yarn_ratios;
DROP POLICY IF EXISTS users_select_yarn_ratios ON public.yarn_ratios;
-- 重新创建策略:允许所有登录用户查看计划(但只能看到分享链接中展示的非敏感字段)
-- 实际敏感信息控制由前端完成
DROP POLICY IF EXISTS purchaser_select_plans ON public.production_plans;
CREATE POLICY users_select_plans ON public.production_plans
FOR SELECT USING (true);
-- yarn_ratios允许查看配合计划查看
DROP POLICY IF EXISTS users_select_yarn_ratios ON public.yarn_ratios;
DROP POLICY IF EXISTS users_insert_yarn_ratios ON public.yarn_ratios;
DROP POLICY IF EXISTS users_update_yarn_ratios ON public.yarn_ratios;
DROP POLICY IF EXISTS users_delete_yarn_ratios ON public.yarn_ratios;
CREATE POLICY users_select_yarn_ratios ON public.yarn_ratios
FOR SELECT USING (true);
CREATE POLICY users_insert_yarn_ratios ON public.yarn_ratios
FOR INSERT WITH CHECK (
company_id = public.get_user_master_company_id()
);
CREATE POLICY users_update_yarn_ratios ON public.yarn_ratios
FOR UPDATE USING (
company_id = public.get_user_master_company_id()
);
CREATE POLICY users_delete_yarn_ratios ON public.yarn_ratios
FOR DELETE USING (
company_id = public.get_user_master_company_id()
);

View File

@ -0,0 +1,52 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 为 products 表添加 RLS 策略
-- 允许查看(用于仓库同步),但只允许公司自己管理
CREATE POLICY users_select_products ON public.products
FOR SELECT USING (true);
CREATE POLICY users_insert_products ON public.products
FOR INSERT WITH CHECK (
company_id = public.get_user_master_company_id()
);
CREATE POLICY users_update_products ON public.products
FOR UPDATE USING (
company_id = public.get_user_master_company_id()
);
CREATE POLICY users_delete_products ON public.products
FOR DELETE USING (
company_id = public.get_user_master_company_id()
);
-- 为 product_inventory_records 表添加 RLS 策略
CREATE POLICY users_select_product_inventory ON public.product_inventory_records
FOR SELECT USING (true);
CREATE POLICY users_insert_product_inventory ON public.product_inventory_records
FOR INSERT WITH CHECK (true);
CREATE POLICY users_update_product_inventory ON public.product_inventory_records
FOR UPDATE USING (true);
CREATE POLICY users_delete_product_inventory ON public.product_inventory_records
FOR DELETE USING (true);
-- 为 product_yarn_ratios 表添加 RLS 策略
CREATE POLICY users_select_product_yarn_ratios ON public.product_yarn_ratios
FOR SELECT USING (true);
CREATE POLICY users_insert_product_yarn_ratios ON public.product_yarn_ratios
FOR INSERT WITH CHECK (true);
CREATE POLICY users_update_product_yarn_ratios ON public.product_yarn_ratios
FOR UPDATE USING (true);
CREATE POLICY users_delete_product_yarn_ratios ON public.product_yarn_ratios
FOR DELETE USING (true);

View File

@ -0,0 +1,32 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 修复 inventory_records 的 RLS 策略
-- 删除旧的策略
DROP POLICY IF EXISTS users_select_company_inventory ON public.inventory_records;
DROP POLICY IF EXISTS users_insert_company_inventory ON public.inventory_records;
DROP POLICY IF EXISTS users_update_company_inventory ON public.inventory_records;
DROP POLICY IF EXISTS users_delete_company_inventory ON public.inventory_records;
-- 创建新的策略:允许查看(用于仓库同步),但只允许公司自己管理
CREATE POLICY users_select_inventory ON public.inventory_records
FOR SELECT USING (true);
CREATE POLICY users_insert_inventory ON public.inventory_records
FOR INSERT WITH CHECK (
company_id = public.get_user_master_company_id()
);
CREATE POLICY users_update_inventory ON public.inventory_records
FOR UPDATE USING (
company_id = public.get_user_master_company_id()
);
CREATE POLICY users_delete_inventory ON public.inventory_records
FOR DELETE USING (
company_id = public.get_user_master_company_id()
);

View File

@ -0,0 +1,34 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 修复 plan_factories 的 RLS 策略
-- 删除旧的策略
DROP POLICY IF EXISTS factory_select_plan_factories ON public.plan_factories;
DROP POLICY IF EXISTS purchaser_select_plan_factories ON public.plan_factories;
DROP POLICY IF EXISTS purchaser_insert_plan_factories ON public.plan_factories;
DROP POLICY IF EXISTS purchaser_delete_plan_factories ON public.plan_factories;
-- 创建新的策略:允许查看(用于仓库同步和分享链接)
CREATE POLICY users_select_plan_factories ON public.plan_factories
FOR SELECT USING (true);
-- 插入和删除保持严格限制
CREATE POLICY users_insert_plan_factories ON public.plan_factories
FOR INSERT WITH CHECK (
EXISTS (
SELECT 1 FROM public.production_plans
WHERE id = plan_id AND purchaser_id = public.get_user_master_company_id()
)
);
CREATE POLICY users_delete_plan_factories ON public.plan_factories
FOR DELETE USING (
EXISTS (
SELECT 1 FROM public.production_plans
WHERE id = plan_id AND purchaser_id = public.get_user_master_company_id()
)
);

View File

@ -0,0 +1,51 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 修复 plan_process_steps 的 RLS 策略
-- 删除旧的策略
DROP POLICY IF EXISTS users_select_process_steps ON public.plan_process_steps;
DROP POLICY IF EXISTS users_insert_process_steps ON public.plan_process_steps;
DROP POLICY IF EXISTS users_update_process_steps ON public.plan_process_steps;
DROP POLICY IF EXISTS users_delete_process_steps ON public.plan_process_steps;
-- 创建新的策略:允许查看(用于流程跟踪)
CREATE POLICY users_select_process_steps ON public.plan_process_steps
FOR SELECT USING (true);
-- 插入:允许关联计划的采购商或工厂
CREATE POLICY users_insert_process_steps ON public.plan_process_steps
FOR INSERT WITH CHECK (
EXISTS (
SELECT 1 FROM public.production_plans p
LEFT JOIN public.plan_factories pf ON p.id = pf.plan_id
WHERE p.id = plan_process_steps.plan_id
AND (p.purchaser_id = public.get_user_master_company_id()
OR pf.factory_id = public.get_user_master_company_id())
)
);
-- 更新:允许关联计划的采购商或工厂
CREATE POLICY users_update_process_steps ON public.plan_process_steps
FOR UPDATE USING (
EXISTS (
SELECT 1 FROM public.production_plans p
LEFT JOIN public.plan_factories pf ON p.id = pf.plan_id
WHERE p.id = plan_process_steps.plan_id
AND (p.purchaser_id = public.get_user_master_company_id()
OR pf.factory_id = public.get_user_master_company_id())
)
);
-- 删除:只允许采购商
CREATE POLICY users_delete_process_steps ON public.plan_process_steps
FOR DELETE USING (
EXISTS (
SELECT 1 FROM public.production_plans
WHERE id = plan_process_steps.plan_id
AND purchaser_id = public.get_user_master_company_id()
)
);

View File

@ -0,0 +1,50 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 修复高风险表的 SELECT 策略
-- 1. production_plans: 只允许采购商查看自己的计划,工厂查看关联的计划
DROP POLICY IF EXISTS users_select_plans ON public.production_plans;
CREATE POLICY users_select_plans ON public.production_plans
FOR SELECT USING (
-- 采购商可以查看自己的计划
purchaser_id = public.get_user_master_company_id()
OR
-- 工厂可以查看关联的计划
EXISTS (
SELECT 1 FROM public.plan_factories
WHERE plan_id = production_plans.id
AND factory_id = public.get_user_master_company_id()
)
);
-- 2. products: 只允许公司自己查看(产品管理)
DROP POLICY IF EXISTS users_select_products ON public.products;
CREATE POLICY users_select_products ON public.products
FOR SELECT USING (
company_id = public.get_user_master_company_id()
);
-- 3. inventory_records: 只允许相关方查看
DROP POLICY IF EXISTS users_select_inventory ON public.inventory_records;
CREATE POLICY users_select_inventory ON public.inventory_records
FOR SELECT USING (
-- 公司可以查看自己的入库记录
company_id = public.get_user_master_company_id()
OR
-- 采购商可以查看关联计划的入库记录
EXISTS (
SELECT 1 FROM public.production_plans p
JOIN public.plan_factories pf ON p.id = pf.plan_id
WHERE p.id = inventory_records.plan_id
AND (p.purchaser_id = public.get_user_master_company_id()
OR pf.factory_id = public.get_user_master_company_id())
)
);

View File

@ -0,0 +1,17 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 1. 删除 PLAN-2026-820523 的重复工厂关联,只保留示例纺织厂
DELETE FROM plan_factories
WHERE plan_id = '7b0d76c2-0bf3-4a58-8607-4dfa850cf416'
AND factory_id = '2da8c512-6076-44e1-8f37-def2298b5847';
-- 2. 检查是否还有其他重复关联
SELECT plan_id, factory_type, COUNT(*)
FROM plan_factories
GROUP BY plan_id, factory_type
HAVING COUNT(*) > 1;

View File

@ -0,0 +1,15 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
-- 添加唯一约束:一个计划的同类型工厂只能关联一个
-- 先删除可能存在的旧约束
ALTER TABLE plan_factories DROP CONSTRAINT IF EXISTS unique_plan_factory_type;
-- 添加新的唯一约束
ALTER TABLE plan_factories
ADD CONSTRAINT unique_plan_factory_type
UNIQUE (plan_id, factory_type);

View File

@ -0,0 +1,6 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
CREATE TABLE IF NOT EXISTS public.audit_logs (id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID REFERENCES auth.users(id) ON DELETE SET NULL, company_id UUID REFERENCES public.companies(id) ON DELETE SET NULL, action TEXT NOT NULL, resource_type TEXT NOT NULL, resource_id UUID, details JSONB, ip_address TEXT, user_agent TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()); CREATE INDEX idx_audit_logs_user_id ON public.audit_logs(user_id); CREATE INDEX idx_audit_logs_company_id ON public.audit_logs(company_id); CREATE INDEX idx_audit_logs_action ON public.audit_logs(action); CREATE INDEX idx_audit_logs_created_at ON public.audit_logs(created_at DESC); ALTER TABLE public.audit_logs ENABLE ROW LEVEL SECURITY; CREATE POLICY users_select_company_audit_logs ON public.audit_logs FOR SELECT USING (company_id = public.get_user_master_company_id()); CREATE POLICY users_insert_audit_logs ON public.audit_logs FOR INSERT WITH CHECK (true);

View File

@ -0,0 +1,6 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
DROP POLICY IF EXISTS users_insert_inventory ON public.inventory_records; CREATE POLICY users_insert_inventory ON public.inventory_records FOR INSERT WITH CHECK (EXISTS (SELECT 1 FROM public.warehouses WHERE id = warehouse_id AND company_id = public.get_user_master_company_id()));

View File

@ -0,0 +1,6 @@
-- ============================================
-- 此文件由 Meoo Cloud 自动生成,请勿修改
-- This file is auto-generated by Meoo Cloud, DO NOT MODIFY
-- ============================================
DROP POLICY IF EXISTS users_insert_payments ON public.payments; CREATE POLICY users_insert_payments ON public.payments FOR INSERT WITH CHECK (from_company_id = public.get_user_master_company_id() OR to_company_id = public.get_user_master_company_id());

Some files were not shown because too many files have changed in this diff Show More