# 汕头市智界科技 IT 服务插件 — 实施计划 > **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** 为汕头市智界科技有限公司创建 freelance(自由职业者工作台)和 itops(IT 运维服务台)两个 WASM 插件,覆盖其全部 12 条经营范围。 **Architecture:** 两个独立的 WASM 插件 crate,每个包含 Cargo.toml(cdylib)、src/lib.rs(Guest trait 实现)、plugin.toml(声明式 schema)。通过插件安装 API 上传到系统,平台自动创建动态表、注册权限、生成前端页面。itops 通过 ref_plugin 跨插件引用 freelance 的 client 实体。 **Tech Stack:** Rust (wit-bindgen 0.55, cdylib → WASM Component)、TOML manifest、Axum Host API **Spec:** `docs/superpowers/specs/2026-04-19-shantou-zhijie-it-services-plugins-design.md` --- ## Chunk 1: freelance 插件 ### Task 1: 创建 crate 目录和 Cargo.toml **Files:** - Create: `crates/erp-plugin-freelance/Cargo.toml` - Create: `crates/erp-plugin-freelance/src/lib.rs`(空文件占位) - [ ] **Step 1: 创建目录结构** ```bash mkdir -p crates/erp-plugin-freelance/src ``` - [ ] **Step 2: 编写 Cargo.toml** 创建 `crates/erp-plugin-freelance/Cargo.toml`: ```toml [package] name = "erp-plugin-freelance" version = "0.1.0" edition = "2024" description = "自由职业者工作台 WASM 插件" [lib] crate-type = ["cdylib"] [dependencies] wit-bindgen = "0.55" ``` - [ ] **Step 3: 编写 src/lib.rs** 创建 `crates/erp-plugin-freelance/src/lib.rs`: ```rust //! 自由职业者工作台 WASM 插件 wit_bindgen::generate!({ path: "../erp-plugin-prototype/wit/plugin.wit", world: "plugin-world", }); use crate::exports::erp::plugin::plugin_api::Guest; struct FreelancePlugin; impl Guest for FreelancePlugin { fn init() -> Result<(), String> { Ok(()) } fn on_tenant_created(_tenant_id: String) -> Result<(), String> { Ok(()) } fn handle_event(_event_type: String, _payload: Vec) -> Result<(), String> { Ok(()) } } export!(FreelancePlugin); ``` - [ ] **Step 4: 注册到 workspace** 编辑根 `Cargo.toml`,在 `members` 数组末尾添加: ```toml "crates/erp-plugin-freelance", ``` - [ ] **Step 5: 验证编译** ```bash cargo check -p erp-plugin-freelance ``` Expected: 编译通过,无错误 - [ ] **Step 6: Commit** ```bash git add crates/erp-plugin-freelance/ Cargo.toml git commit -m "feat(freelance): 创建插件 crate 骨架" ``` --- ### Task 2: 编写 plugin.toml(freelance) **Files:** - Create: `crates/erp-plugin-freelance/plugin.toml` - [ ] **Step 1: 从设计规格文档复制完整 plugin.toml 内容** 从设计规格 `docs/superpowers/specs/2026-04-19-shantou-zhijie-it-services-plugins-design.md` 中提取 2.1(元数据)+ 2.2(权限)+ 2.3(10 个实体)+ 2.4(编号规则)+ 2.5(页面声明)的所有 TOML 内容,合并为完整的 `plugin.toml` 文件。 文件结构: 1. `[metadata]` 段 2. `[[permissions]]` × 20 3. `[[schema.entities]]` × 10(client, opportunity, quote, quote_line, contract, project, task, time_entry, invoice, expense),每个实体包含 fields 和 relations 4. `[[numbering]]` × 3(quote_number, contract_number, invoice_number) 5. `[[ui.pages]]` × 7(dashboard, tabs+detail+kanban for client, crud+detail for project, tabs for finance, crud for expense) 注意要点: - client 实体必须标记 `is_public = true`(被 itops 跨插件引用) - quote 到 quote_line 有 cascade 关系 - project 到 task 和 time_entry 有 cascade 关系 - 所有 uuid 引用字段使用 `ui_widget = "entity_select"` + `ref_label_field` + `ref_search_fields` - 所有 select 字段使用 `options = [{ label = "X", value = "x" }]` 格式 - 长文本使用 `field_type = "string"` + `ui_widget = "textarea"` - 金额使用 `field_type = "decimal"` - 时间戳使用 `field_type = "date_time"` - [ ] **Step 2: 验证 TOML 格式** ```bash cargo check -p erp-plugin-freelance ``` - [ ] **Step 3: Commit** ```bash git add crates/erp-plugin-freelance/plugin.toml git commit -m "feat(freelance): 添加 plugin.toml — 10 实体/20 权限/7 页面" ``` --- ### Task 3: 编译 WASM 并安装 - [ ] **Step 1: 编译为 WASM** ```bash cargo build -p erp-plugin-freelance --target wasm32-unknown-unknown --release ``` Expected: 编译成功,产出 `target/wasm32-unknown-unknown/release/erp_plugin_freelance.wasm` - [ ] **Step 2: 转换为 Component** ```bash wasm-tools component new target/wasm32-unknown-unknown/release/erp_plugin_freelance.wasm -o target/erp_plugin_freelance.component.wasm ``` - [ ] **Step 3: 检查产物大小** ```bash ls -la target/erp_plugin_freelance.component.wasm ``` Expected: < 100KB(CRM 约 22KB) - [ ] **Step 4: 启动后端服务** ```bash cd crates/erp-server && cargo run ``` 等待服务启动完成(看到 "listening on 0.0.0.0:3000" 日志) - [ ] **Step 5: 登录获取 Token** ```bash curl -s -X POST http://localhost:3000/api/v1/auth/login \ -H "Content-Type: application/json" \ -d '{"username":"admin","password":"admin123"}' | jq -r '.data.access_token' ``` 保存输出的 token。 - [ ] **Step 6: 上传安装插件** ```bash TOKEN="<上一步的 token>" MANIFEST=$(cat crates/erp-plugin-freelance/plugin.toml) curl -s -X POST http://localhost:3000/api/v1/admin/plugins/upload \ -H "Authorization: Bearer $TOKEN" \ -F "wasm=@target/erp_plugin_freelance.component.wasm" \ -F "manifest=$MANIST" ``` Expected: 返回插件 ID,状态为 `installed` - [ ] **Step 7: 启用插件** 使用上一步返回的插件 ID: ```bash PLUGIN_ID="<返回的插件 ID>" curl -s -X POST "http://localhost:3000/api/v1/admin/plugins/$PLUGIN_ID/enable" \ -H "Authorization: Bearer $TOKEN" ``` Expected: 状态变为 `running` - [ ] **Step 8: Commit** ```bash git add -A git commit -m "feat(freelance): 编译 WASM 并验证安装" ``` --- ### Task 4: 浏览器验证 freelance 插件 - [ ] **Step 1: 打开浏览器访问 http://localhost:5174** - [ ] **Step 2: 登录后检查侧边栏** Expected: 看到"自由职业者工作台"菜单组,包含:工作台、客户管理、商机看板、项目管理、项目详情、财务中心、支出管理 - [ ] **Step 3: 测试客户 CRUD** 进入客户管理 → 新增客户(填写名称、联系人、电话、行业等)→ 保存 → 列表中可见 - [ ] **Step 4: 测试项目 → 任务级联** 进入项目管理 → 新增项目 → 进入项目详情 → 新增任务 → 验证任务关联到项目 - [ ] **Step 5: 测试报价 → 报价明细级联** 进入财务中心 → 报价管理 tab → 新增报价 → 验证明细行可添加 - [ ] **Step 6: 测试商机看板** 进入商机看板 → 新增商机 → 拖拽改变阶段 → 验证数据更新 - [ ] **Step 7: 验证数据库表创建** ```bash PGPASSWORD=123123 "D:\postgreSQL\bin\psql.exe" -U postgres -h localhost -d erp -c "\dt plugin_erp_freelance_*" ``` Expected: 看到 10 张动态表 --- ## Chunk 2: itops 插件 ### Task 5: 创建 itops 插件 crate **Files:** - Create: `crates/erp-plugin-itops/Cargo.toml` - Create: `crates/erp-plugin-itops/src/lib.rs` - Create: `crates/erp-plugin-itops/plugin.toml` - [ ] **Step 1: 创建目录结构** ```bash mkdir -p crates/erp-plugin-itops/src ``` - [ ] **Step 2: 编写 Cargo.toml** 创建 `crates/erp-plugin-itops/Cargo.toml`: ```toml [package] name = "erp-plugin-itops" version = "0.1.0" edition = "2024" description = "IT 运维服务台 WASM 插件" [lib] crate-type = ["cdylib"] [dependencies] wit-bindgen = "0.55" ``` - [ ] **Step 3: 编写 src/lib.rs** 创建 `crates/erp-plugin-itops/src/lib.rs`: ```rust //! IT 运维服务台 WASM 插件 wit_bindgen::generate!({ path: "../erp-plugin-prototype/wit/plugin.wit", world: "plugin-world", }); use crate::exports::erp::plugin::plugin_api::Guest; struct ItopsPlugin; impl Guest for ItopsPlugin { fn init() -> Result<(), String> { Ok(()) } fn on_tenant_created(_tenant_id: String) -> Result<(), String> { Ok(()) } fn handle_event(_event_type: String, _payload: Vec) -> Result<(), String> { Ok(()) } } export!(ItopsPlugin); ``` - [ ] **Step 4: 编写 plugin.toml** 从设计规格文档 Section 3 提取完整内容: 1. `[metadata]` — id="erp-itops",无 dependencies(松耦合) 2. `[[permissions]]` × 8 3. `[[schema.entities]]` × 4(service_contract, ticket, check_plan, check_record),每个实体包含 fields 和 relations 4. `[[numbering]]` × 1(contract_number) 5. `[[ui.pages]]` × 4(crud+detail for service_contract, tabs for ticket center) 关键注意点: - 4 个实体的 `client_id` 字段都使用 `ref_plugin = "erp-freelance"` + `ref_fallback_label = "外部客户"` - `filterable` 只用于 string 类型的 status/type/category 字段,不用于 uuid 字段 - `check_items` 和 `items_data` 使用 `field_type = "json"` - `responded_at` / `resolved_at` / `closed_at` 使用 `field_type = "date_time"` - [ ] **Step 5: 注册到 workspace** 编辑根 `Cargo.toml`,在 members 数组末尾添加: ```toml "crates/erp-plugin-itops", ``` - [ ] **Step 6: 验证编译** ```bash cargo check -p erp-plugin-itops ``` - [ ] **Step 7: Commit** ```bash git add crates/erp-plugin-itops/ Cargo.toml git commit -m "feat(itops): 创建 IT 运维服务台插件 — 4 实体/8 权限/4 页面" ``` --- ### Task 6: 编译 WASM 并安装 itops - [ ] **Step 1: 编译为 WASM** ```bash cargo build -p erp-plugin-itops --target wasm32-unknown-unknown --release ``` - [ ] **Step 2: 转换为 Component** ```bash wasm-tools component new target/wasm32-unknown-unknown/release/erp_plugin_itops.wasm -o target/erp_plugin_itops.component.wasm ``` - [ ] **Step 3: 上传安装插件** ```bash TOKEN="<之前获取的 token>" MANIFEST=$(cat crates/erp-plugin-itops/plugin.toml) curl -s -X POST http://localhost:3000/api/v1/admin/plugins/upload \ -H "Authorization: Bearer $TOKEN" \ -F "wasm=@target/erp_plugin_itops.component.wasm" \ -F "manifest=$MANIFEST" ``` - [ ] **Step 4: 启用插件** ```bash PLUGIN_ID="<返回的插件 ID>" curl -s -X POST "http://localhost:3000/api/v1/admin/plugins/$PLUGIN_ID/enable" \ -H "Authorization: Bearer $TOKEN" ``` --- ### Task 7: 浏览器验证 itops 插件 - [ ] **Step 1: 检查侧边栏** Expected: 看到"IT 运维服务台"菜单组,包含:合同管理、合同详情、工单中心 - [ ] **Step 2: 测试维保合同 CRUD** 进入合同管理 → 新增维保合同(选择客户时验证:如 freelance 已安装,客户下拉显示 freelance 的客户列表) - [ ] **Step 3: 测试跨插件引用** 场景 A(freelance 已安装):创建工单时 client_id 字段显示为下拉选择器,可搜索 freelance.client 场景 B(freelance 未安装):client_id 降级为文本输入,显示"外部客户" - [ ] **Step 4: 测试合同 → 工单 → 巡检级联** 进入合同详情 → 工单 tab → 新增工单 → 巡检计划 tab → 新增巡检计划 → 巡检记录 tab → 新增巡检记录 - [ ] **Step 5: 验证数据库表** ```bash PGPASSWORD=123123 "D:\postgreSQL\bin\psql.exe" -U postgres -h localhost -d erp -c "\dt plugin_erp_itops_*" ``` Expected: 看到 4 张动态表 --- ## Chunk 3: 集成验证 ### Task 8: 全链路端到端验证 - [ ] **Step 1: 创建客户** freelance → 客户管理 → 新增客户"汕头市XX科技有限公司" - [ ] **Step 2: 创建商机** 商机看板 → 新增商机 → 选择客户 → 填写"官网开发"→ 拖拽到"成交"阶段 - [ ] **Step 3: 创建报价单** 财务中心 → 报价管理 → 新增报价 → 选择客户 → 添加明细行 → 保存 - [ ] **Step 4: 创建合同** 财务中心 → 合同管理 → 新增合同 → 选择客户 → 填写金额和日期 → 保存 - [ ] **Step 5: 创建项目** 项目管理 → 新增项目 → 选择客户和合同 → 填写"官网开发项目" → 添加任务 → 记录工时 - [ ] **Step 6: 创建发票** 财务中心 → 发票/收款 → 新增发票 → 选择客户和项目 → 填写金额 → 标记已收款 - [ ] **Step 7: 创建运维工单** itops → 合同管理 → 新增维保合同 → 选择客户(验证跨插件引用)→ 保存 itops → 工单中心 → 新增工单 → 选择客户和合同 → 保存 - [ ] **Step 8: 记录支出** freelance → 支出管理 → 新增支出 → 选择类别"云服务" → 填写金额 → 保存 - [ ] **Step 9: 提交并推送** ```bash git add -A git commit -m "feat(freelance,itops): 汕头市智界科技 IT 服务行业插件验证通过" git push ``` --- ## 关键参考文件 | 文件 | 用途 | |------|------| | `crates/erp-plugin-crm/Cargo.toml` | Cargo.toml 模板参考 | | `crates/erp-plugin-crm/src/lib.rs` | lib.rs 代码模式参考 | | `crates/erp-plugin-crm/plugin.toml` | plugin.toml 格式参考(同插件内引用) | | `crates/erp-plugin-inventory/plugin.toml` | 跨插件引用格式参考(ref_plugin) | | `crates/erp-plugin/src/manifest.rs` | PluginField/PluginFieldType 完整定义 | | `crates/erp-plugin-prototype/wit/plugin.wit` | WIT 接口定义 | | `wiki/infrastructure.md` | 数据库连接、端口、登录凭据 | | `wiki/wasm-plugin.md` | 插件制作完整流程 |