Skip to content

P2 Modules Implementation Plan ​

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: 落地 4 个生态向能力:行业包、协同(锁+评论+分支)、私有化 AI、插件清单加载。全部建立在 P0 的 snapshot / adapter / protocol 之上。

Architecture: 行业包和插件都是「远程清单 + 本地 addDragRule/setBehavior」,不在运行时执行任意字符串。协同不做 CRDT。私有化 AI 只保证 OpenAI 兼容协议和离线依赖清单。

Tech Stack: 现有 list / addDragRule / config.ai / _fc_id。

Spec: docs/superpowers/specs/2026-08-23-innovation-requirements.md §4 P2


P2-1 行业包 + 模板市场 ​

File map ​

  • Create: designer3.0/src/modules/marketplace/loadPack.js
  • Create: designer3.0/tests/modules/marketplace/loadPack.spec.js
  • Create: designer3.0/packs/hr/index.js
  • Create: designer3.0/packs/expense/index.js
  • Create: designer3.0/packs/gov-apply/index.js
  • Modify: designer3.0/src/designer/FcDesigner.vue — config.packUrl 启动时拉取

包格式:

js
export const pack = {
    name: 'fc-pack-hr',
    version: '1.0.0',
    list: [{ label: '入职登记', rule: [], options: { formName: '入职登记' } }],
    dragRules: [],
};

Task 1: loadPack ​

  • [ ] Step 1: 测试
js
import { applyPack } from '../../../src/modules/marketplace/loadPack.js';

it('merges list items onto designer list', () => {
    const designer = { addComponent: () => {}, list: [] };
    applyPack(designer, { name: 'hr', version: '1.0.0', list: [{ label: '入职', rule: [] }], dragRules: [] });
    expect(designer.list).toHaveLength(1);
});

it('rejects pack without name', () => {
    expect(() => applyPack({}, { list: [] })).toThrow('invalid_pack');
});

applyPack 只接受普通对象,不 eval。dragRules 若来自远程 URL,必须是已经在宿主 import() 过的模块,URL 清单只提供 {name, module} 映射。

  • [ ] Step 2: 三个官方包内容

  • HR:姓名、身份证、部门、入职日、紧急联系人(group)。

  • 费用:金额(用现有 chineseAmount 模板)、事由、发票上传、日期。

  • 政务:申请人、证件号、事项类型、材料上传、声明 checkbox。

规则用手写 JSON,放到 packs/*/rules/*.json,index.js 读取。不要用 AI 生成后不检查。

  • [ ] Step 3: 设计器接入

config.packs 为本地模块数组;config.packCatalogUrl 只拉 {name, version, importPath} JSON。examples 演示加载 packs/hr。

bash
git add src/modules/marketplace packs
git commit -m "feat: industry packs and pack loader"

P2-2 协同:锁、评论、分支 ​

File map ​

  • Create: designer3.0/src/modules/collab/lock.js
  • Create: designer3.0/src/modules/collab/comments.js
  • Create: designer3.0/tests/modules/collab/lock.spec.js
  • Create: designer3.0/src/designer/collab/CommentPane.vue
  • Modify: designer3.0/src/designer/FcDesigner.vue — beforeActiveRule 结合锁
  • Modify: designer3.0/types/index.d.ts — HostAdapter.lockField / addComment

Task 1: 字段锁 ​

  • [ ] Step 1: 测试
js
import { canEdit, acquireLock, releaseLock } from '../../../src/modules/collab/lock.js';

it('blocks another user', () => {
    const locks = acquireLock({}, 'id_name', 'u1');
    expect(canEdit(locks, 'id_name', 'u1')).toBe(true);
    expect(canEdit(locks, 'id_name', 'u2')).toBe(false);
    const next = releaseLock(locks, 'id_name', 'u1');
    expect(canEdit(next, 'id_name', 'u2')).toBe(true);
});

锁 map:{ [fcId]: { userId, at } }。超时不在第一期做,由 adapter 心跳决定。

  • [ ] Step 2: 评论

评论对象:{ id, fcId, userId, text, at }。CommentPane 按当前 activeRule._fc_id 过滤。adapter listComments / addComment。无 adapter 时面板显示「需协同适配器」。

  • [ ] Step 3: 分支

「另存为分支」= saveForm 一份新 snapshot,options.branchOf = oldFormId。复用版本面板,不新做 git merge。

bash
git add src/modules/collab src/designer/collab
git commit -m "feat: field locks comments and snapshot branches"

P2-3 私有化 AI 与信创离线 ​

File map ​

  • Create: designer3.0/src/modules/ai/openaiCompat.js
  • Create: designer3.0/tests/modules/ai/openaiCompat.spec.js
  • Create: fc-design-pro/src/help/feature/private-ai.md
  • Create: fc-design-pro/src/help/feature/offline.md
  • Modify: designer3.0/src/designer/ai/AiPanel.vue — 请求改走 openaiCompat

Task 1: OpenAI 兼容客户端 ​

  • [ ] Step 1: 测试
js
import { buildChatRequest } from '../../../src/modules/ai/openaiCompat.js';

it('builds chat completions payload', () => {
    const req = buildChatRequest({
        model: 'local-model',
        messages: [{ role: 'user', content: '做个请假表' }],
        thinking: false,
    });
    expect(req.urlPath).toBe('/v1/chat/completions');
    expect(req.body.model).toBe('local-model');
    expect(req.body.messages[0].content).toBe('做个请假表');
});

config.ai.api 已存在。补 config.ai.model、config.ai.path(默认 /v1/chat/completions)。AiPanel 不要写死官方主机路径以外的假设;空 api 才用内置默认。

  • [ ] Step 2: 离线文档

对照 开发环境与依赖说明.md §4.3,列出:echarts、mermaid、xlsx、mammoth、html2canvas、jspdf、pdfjs。offline.md 给出用 formCreateUrl 同类本地托管的配置示例。不把模型文件打进仓库。

bash
git add src/modules/ai src/designer/ai
git commit -m "feat: OpenAI-compatible private AI client"

P2-4 插件清单 ​

File map ​

  • Create: designer3.0/src/modules/plugin/validateManifest.js
  • Create: designer3.0/src/modules/plugin/usePlugin.js
  • Create: designer3.0/tests/modules/plugin/usePlugin.spec.js
  • Create: designer3.0/src/extension/plugin.example.json
  • Modify: designer3.0/src/index.js — FcDesigner.usePlugin
  • Modify: designer3.0/types/index.d.ts

清单:

json
{
    "name": "fc-plugin-id-card",
    "version": "1.0.0",
    "menus": [{ "name": "biz", "title": "业务" }],
    "dragRuleNames": ["idCard"],
    "behaviors": ["exportIdCard"],
    "formulas": ["CHECK_ID"]
}

Task 1: usePlugin ​

  • [ ] Step 1: 测试
js
import { usePlugin } from '../../../src/modules/plugin/usePlugin.js';

it('registers menus and rules from module maps', () => {
    const calls = { menus: [], rules: [] };
    const Fc = {
        addMenu: (m) => calls.menus.push(m),
        addDragRule: (r) => calls.rules.push(r),
        setBehavior: () => {},
        setFormula: () => {},
    };
    usePlugin(
        Fc,
        { name: 'p', version: '1', menus: [{ name: 'biz', title: '业务' }], dragRuleNames: ['idCard'] },
        { dragRules: { idCard: { name: 'idCard', menu: 'biz', label: '身份证' } } }
    );
    expect(calls.menus[0].name).toBe('biz');
    expect(calls.rules[0].name).toBe('idCard');
});

it('refuses missing module entry', () => {
    expect(() =>
        usePlugin({ addMenu() {}, addDragRule() {} }, { name: 'p', version: '1', dragRuleNames: ['x'] }, { dragRules: {} })
    ).toThrow('plugin_export_missing');
});

远程商店只返回清单 URL。真正代码必须由宿主 import 后传入第三参。禁止根据 URL 拼 script 执行。

bash
git add src/modules/plugin src/index.js types/index.d.ts
git commit -m "feat: plugin manifest loader"