Skip to content

P1 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: 落地 6 个 P1 子系统:双模设计器、跨运行时协议+React 子集、数据中台合同、套打、运行时 AI、移动端覆盖。每个子系统可独立发版。

Architecture: 全部以 src/modules/<name> 纯逻辑 + 可选 UI 接入。双模最先做(只改配置)。React 渲染器放独立目录 designer3.0/packages/react-renderer/,不进主包,避免 Vue 客户买单体积。

Tech Stack: 现有 Config.show*、Rule JSON、Vant 移动端、html2canvas 打印(套打会替换主路径)。

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


P1-5 双模设计器(先做) ​

File map ​

  • Modify: designer3.0/src/modules/shared/modePreset.js(已在 foundation)
  • Modify: designer3.0/src/designer/FcDesigner.vue — 启动时 resolveDesignerConfig
  • Create: designer3.0/src/designer/ModeSwitch.vue
  • Modify: designer3.0/types/index.d.ts — Config.mode、allowModeSwitch

Task 1: 接入 mode ​

  • [ ] Step 1: 在 getConfig 源头合并预设

找到 getConfig(FcDesigner.vue)。改为:

js
getConfig(key) {
    const merged = resolveDesignerConfig(props.config || {});
    if (key) return merged[key];
    return merged;
}

确认所有 getConfig('showXxx') 都走这一处,不要只改部分调用。

  • [ ] Step 2: ModeSwitch

工具栏最右侧。config.allowModeSwitch === true 时显示。切换只改本地 data.modeOverride,再与 props.config 合并,不写回宿主除非 emit update:mode。

  • [ ] Step 3: 验收

config.mode='business' 打开设计器:左侧无 JSON,右侧无事件,预览无 SFC/SQL。allowModeSwitch: true 切回 developer 后这些入口回来。

bash
git add src/designer/FcDesigner.vue src/designer/ModeSwitch.vue types/index.d.ts src/locale
git commit -m "feat: business and developer designer modes"

P1-1 跨运行时协议 + React 子集 ​

File map ​

  • Create: designer3.0/src/modules/protocol/whitelist.js
  • Create: designer3.0/src/modules/protocol/lintRule.js
  • Create: designer3.0/tests/modules/protocol/lintRule.spec.js
  • Create: designer3.0/packages/react-renderer/package.json
  • Create: designer3.0/packages/react-renderer/src/FcForm.jsx
  • Create: designer3.0/packages/react-renderer/src/widgets/index.js
  • Create: fc-design-pro/src/protocol.md

白名单第一期:input textarea number password select radio checkbox switch date dateRange time upload rate slider cascader treeSelect group。

Task 1: 协议检查 ​

  • [ ] Step 1: 写失败测试
js
import { lintRule } from '../../../src/modules/protocol/lintRule.js';

it('flags unknown types', () => {
    const report = lintRule([{ type: 'fcVxeDataTable', field: 't' }]);
    expect(report.ok).toBe(false);
    expect(report.issues[0].code).toBe('type_not_portable');
});

it('accepts core inputs', () => {
    expect(lintRule([{ type: 'input', field: 'n' }]).ok).toBe(true);
});
  • [ ] Step 2: 实现

lintRule 递归 children。未知 type → type_not_portable。含函数的 on / control.handle 标 runtime_fn warning,不判失败(React 一期可以忽略事件)。

预览增加「跨端检查」小报告,config.showProtocolLint === true 时显示。

  • [ ] Step 3: React 渲染器最小集

packages/react-renderer 使用 antd Input/Select。FcForm props:rule option value onChange。只实现白名单组件;遇到其它 type 渲染一个只读占位「不支持的组件:type」。

不把该包打进 dist/index.es.js。单独 package.json name @form-create/react。

bash
git add src/modules/protocol packages/react-renderer
git commit -m "feat: portable rule lint and react subset renderer"

P1-2 数据中台合同 + 参考服务 ​

File map ​

  • Modify: designer3.0/src/modules/shared/adapter.js — shareLink / listStats
  • Create: designer3.0/examples/platform/data-service/README.md
  • Create: designer3.0/examples/platform/data-service/server.mjs
  • Modify: fc-design-pro/src/database.md — 声明演示云 ≠ 产品后端
  • Modify: designer3.0/examples/components/SaveFormModel.vue — 顶部注释 + UI 提示「演示」

Task 1: 扩展 adapter ​

  • [ ] Step 1: 测试
js
it('creates a share token for published form', async () => {
    const adapter = createMemoryAdapter();
    const { id } = await adapter.saveForm({ snapshot: { format: '1.0.0', formId: 'f1', name: 'n', rule: [], options: {}, schema: [], createdAt: '' }, rule: '[]', options: '{}' });
    await adapter.publishVersion(id, 1);
    const share = await adapter.createShare({ formId: id, version: 1 });
    expect(share.token).toBeTruthy();
    const open = await adapter.getShare(share.token);
    expect(open.formId).toBe(id);
});
  • [ ] Step 2: 参考服务

server.mjs 用 Node 内置 http,内存存储,路由:

  • POST /forms → saveForm
  • GET /forms/:id/versions
  • POST /forms/:id/records
  • GET /forms/:id/records
  • POST /share
  • GET /s/:token

不要引入 Nest/Express 全家桶。README 写清「参考实现,生产请换」。

bash
git add src/modules/shared/adapter.js examples/platform
git commit -m "feat: share adapter and reference data service"

P1-3 套打设计器 ​

File map ​

  • Create: designer3.0/src/modules/print/types.js
  • Create: designer3.0/src/modules/print/bindTemplate.js
  • Create: designer3.0/tests/modules/print/bindTemplate.spec.js
  • Create: designer3.0/src/designer/print/PrintDesigner.vue
  • Modify: designer3.0/src/utils/extendPrintApi.js — printTemplate
  • Modify: designer3.0/src/designer/PrintForm.vue

模板结构:

js
{
  id: 'print_default',
  page: { width: 210, height: 297, unit: 'mm' },
  background: '',
  items: [{ id, x, y, w, h, text: '{{name}}' }],
  repeat: { field: 'items', y: 120, height: 8, items: [{ text: '{{name}}', x: 20 }] }
}

Task 1: 绑定纯函数 ​

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

it('replaces mustache fields', () => {
    const html = bindTemplate(
        { page: { width: 210, height: 297, unit: 'mm' }, items: [{ x: 10, y: 10, w: 80, h: 8, text: '姓名:{{name}}' }], repeat: null },
        { name: '张三' }
    );
    expect(html).toContain('姓名:张三');
    expect(html).toContain('210mm');
});
  • [ ] Step 2: PrintDesigner

画布按 mm 换算 px(1mm = 3.78px)。从当前表单 field 列表拖「数据域」到画布。背景图 input。存 options.printTemplates[]。

  • [ ] Step 3: 运行时

api.printTemplate(id) 用 bindTemplate 生成 HTML,window.print()。默认模板仍可走旧 html2canvas,避免行为突变。

bash
git add src/modules/print src/designer/print src/utils/extendPrintApi.js
git commit -m "feat: print template designer with field binding"

P1-4 运行时 AI Agent ​

File map ​

  • Create: designer3.0/src/modules/runtime-ai/tools.js
  • Create: designer3.0/src/modules/runtime-ai/runAgent.js
  • Create: designer3.0/tests/modules/runtime-ai/tools.spec.js
  • Create: designer3.0/src/form/FcAiAgent.js
  • Create: fc-design-pro/src/help/feature/runtime-ai.md

允许的工具:setValue {field,value}、getValue {field}、validate {}、explainField {field}。

Task 1: 工具白名单 ​

  • [ ] Step 1: 测试
js
import { executeTool } from '../../../src/modules/runtime-ai/tools.js';

it('sets a value via api', () => {
    const api = { setValue: (f, v) => (store[f] = v), getValue: (f) => store[f] };
    const store = { name: '' };
    executeTool(api, { name: 'setValue', args: { field: 'name', value: 'A' } });
    expect(store.name).toBe('A');
});

it('rejects unknown tools', () => {
    expect(() => executeTool({}, { name: 'eval', args: {} })).toThrow('tool_not_allowed');
});
  • [ ] Step 2: runAgent

循环最多 4 步:把 schema 摘要 + formData + 用户话发给 adapter.chat 或 config.ai。模型必须返回 {reply, tool?} JSON。执行 tool 后再问一次。禁止把 on 函数源码送给模型去改。

  • [ ] Step 3: 插件
js
formCreate.use(FcAiAgent, { ai, enabled: false });

默认 enabled false。设计器预览用同一插件。

bash
git add src/modules/runtime-ai src/form/FcAiAgent.js
git commit -m "feat: runtime AI agent with allowlisted form tools"

P1-6 移动端覆盖 + 渠道 ​

File map ​

  • Create: designer3.0/src/modules/mobile/coverage.js
  • Create: designer3.0/tests/modules/mobile/coverage.spec.js
  • Modify: 每个复杂 DragRule(至少 tableForm fcVxeDataTable nestedTableForm dataTable)增加 mobile: 'fallback' | 'hidden'
  • Create: designer3.0/src/components/mobile/TableFormFallback.vue
  • Create: fc-design-pro/src/help/feature/mobile-coverage.md

Task 1: 覆盖表 ​

  • [ ] Step 1: 从 menu 收集 name,对照 src/form/mobile.js 已注册组件,生成 coverage 报告函数
js
export function mobileCoverage(dragRules, mobileTypes) {
    return dragRules.map((r) => ({
        name: r.name,
        status: mobileTypes.includes(r.name) ? 'native' : r.mobile || 'hidden',
    }));
}

测试:native / fallback / hidden 三态。

  • [ ] Step 2: TableFormFallback

移动端把每一行渲染成 Card,字段纵向排列。注册到 formCreateMobile。

  • [ ] Step 3: 微信渠道文档

fc-design-pro/src/help/feature/miniprogram.md:只输出白名单 JSON,小程序端用官方示例仓库(本计划不写完整小程序项目,避免范围爆炸)。设计器增加 getPortableJson() = lintRule 通过后的 rule。

bash
git add src/modules/mobile src/components/mobile
git commit -m "feat: mobile coverage report and table fallback"