# @gct-paas/word

GCT 在线 Word 文档引擎与 Vue 组件 SDK，用于在业务系统中接入文档设计、渲染与表单填报能力。

## 适用场景

- 需要在 Vue 3 项目中嵌入在线文档设计器/预览器
- 需要统一接入文档实例、模板、填报数据能力
- 需要通过插件机制扩展套件能力（如 `edhr`）

## 环境要求

- Node.js >= 18
- Vue 3

## 安装

```bash
pnpm add @gct-paas/word
```

或：

```bash
npm install @gct-paas/word
```

或：

```bash
yarn add @gct-paas/word
```

## 依赖与样式

请在宿主项目中安装/确保以下 peer dependencies 可用（以 `package.json` 为准），包括但不限于：

- `vue`
- `floating-vue`
- `vue-konva`
- `konva`
- `vxe-table`
- `vuedraggable`
- `sortablejs`
- `crypto-js`
- `jspdf`
- `qrcode`
- `jsbarcode`
- `exifr`

同时引入样式文件：

```ts
import '@gct-paas/word/style.css';
```

## 快速开始

下面示例展示从初始化宿主适配器，到创建运行时，再到挂载渲染组件的完整流程。

```ts
import { createApp, defineComponent } from 'vue';
import {
  setupPlatformAdapters,
  setupVueRuntime,
  useWord,
  DocRenderLayout,
  edhrSuitePlugin,
} from '@gct-paas/word';
import '@gct-paas/word/style.css';

// 1) 应用全局初始化（整个应用生命周期调用一次）
setupPlatformAdapters({
  interceptors: {
    requestInterceptors: (config: any) => config,
    requestInterceptorsCatch: (error: any) => Promise.reject(error),
    responseInterceptors: (response: any) => response,
    responseInterceptorsCatch: (error: any) => Promise.reject(error),
  },
  getAppInfo: async () => ({}),
  parseFile: async (file: File) => file,
  uploadFile: async (file: File) => ({ url: '', name: file.name }),
  formulaIdentify: async () => [],
  formulaCalculate: async () => ({}),
  triggerHandler: async () => void 0,
  plugins: [edhrSuitePlugin],
});

const Root = defineComponent({
  name: 'WordDemo',
  components: { DocRenderLayout },
  setup() {
    // 2) 创建文档运行时
    const { controller, docInfo } = useWord(
      {
        requestId: 'your-request-id',
        materialNo: 'optional-material-no',
        requestQuery: {},
      },
      {
        factoryType: 'instance', // 'template' | 'instance'
        modelKey: 'fm_your_model_key',
        suiteKey: 'edhr',
        isPreview: true,
      },
    );

    return { controller, docInfo };
  },
  template: `
    <div style="height: 100vh;">
      <DocRenderLayout />
    </div>
  `,
});

const app = createApp(Root);

// 3) Vue 运行时初始化（createApp 后调用）
setupVueRuntime({ app });
app.mount('#app');
```

## 初始化 API

### `setupPlatformAdapters(options)`

平台适配器注册函数。用于将宿主系统能力注入 SDK，全局只需调用一次。

`options` 关键字段：

- `interceptors`：HTTP 请求拦截器配置
- `getAppInfo`：获取应用信息/默认上下文
- `parseFile`：文件解析方法
- `uploadFile`：文件上传方法
- `formulaIdentify?`：公式变量识别（可选）
- `formulaCalculate?`：公式计算（可选）
- `triggerHandler?`：触发主工程交互（可选）
- `plugins?`：要安装的 suite 插件列表（如 `edhrSuitePlugin`）

### `setupVueRuntime({ app })`

Vue 运行时注册函数。建议在 `createApp` 后、`mount` 前调用。

作用：

- 注册 `FloatingVue`
- 注册 `VueKonva`
- 注册 SDK 所需全局指令

## 核心运行时 API

### `useWord(props, options)`

文档运行时主入口，返回 `WordRuntime`。

- `props.requestId`：文档实例 ID 或模板 ID（支持函数形式）
- `options.factoryType`：`'template' | 'instance'`
- `options.modelKey`：主模型 key
- `options.suiteKey?`：套件 key（默认常用 `edhr`）
- `options.isPreview?` / `options.isDetailPage?` / `options.renderModeType?`：运行模式控制

返回值：

- `controller`：`ShallowRef<DocController | null>`
- `docInfo`：`Ref<DocInfo>`

### `DocController`（对外 API 清单）

`controller.value` 可用后，主要分为 4 类能力：

1. 状态字段（响应式）：

- `id: string`：当前文档实例 id
- `mode`：当前渲染模式
- `modeLabel`：渲染模式文案
- `updateTick`：布局刷新计数
- `pages`：当前页面数组
- `docRuntimeMeta`：运行时元信息（接口返回 + 业务拼接）

2. 查询 API（只读）：

- `query.getWidgetByModelId(modelId)`：按模型字段 id 定位组件节点
- `query.getPaperBySecRefId(id)`：按分节 refId 定位页面

3. 编辑/控制 API：

- `execute(command, payload?)`：执行内置命令（高级）
- `undo()` / `redo()`：撤销与重做
- `setMode(mode)`：切换渲染模式
- `setModel(model)`：替换当前文档模型
- `rawData()`：获取原始填报数据
- `reload()`：手动触发文档重载

4. 数据处理 API：

- `validate()`：校验字段，返回错误映射或 `null`
- `exportModel()`：导出 XmlJson 模型数据
- `getDocumentAttachmentPaths(types?)`：提取附件路径列表
- `enterBaseline(uniqueId)`：记录基线并进入填报模式
- `computeBaselineChanges(ctx)`：计算与基线差异
- `setAnnotation(ids, list)`：设置批注

示例：

```ts
const c = controller.value;
if (!c) return;

const errors = await c.validate();
if (!errors) {
  const model = c.exportModel();
  const data = c.rawData();
  const files = c.getDocumentAttachmentPaths();
  console.log(model, data, files);
}
```

## 对外导出（主入口）

当前包主入口为 `@gct-paas/word`，可直接使用以下能力：

- 初始化 API：`setupPlatformAdapters`、`setupVueRuntime`
- 引擎/类型：`useWord`、`DocModeTypeConst`、`PageSizeEnumConst`、`BuiltinComponentTypeConst`、`WordRuntime`、`DocController` 等
- Vue 组件：`DocDesignLayout`、`DocRenderLayout`、`GctLayout`
- 插件能力：`registerSuite`、`WordSuitePlugin`、`edhrSuitePlugin`、`registerPanelSchemas`

## 插件扩展

### 方式一：在 `setupPlatformAdapters` 里批量注册（推荐）

```ts
import { setupPlatformAdapters, edhrSuitePlugin } from '@gct-paas/word';

setupPlatformAdapters({
  interceptors,
  getAppInfo,
  parseFile,
  uploadFile,
  plugins: [edhrSuitePlugin],
});
```

### 方式二：手动调用 `registerSuite`

```ts
import { registerSuite, edhrSuitePlugin } from '@gct-paas/word';

registerSuite(edhrSuitePlugin);
```

### 自定义插件协议

```ts
import type { WordSuitePlugin } from '@gct-paas/word';

const customPlugin: WordSuitePlugin = {
  key: 'custom-suite',
  install() {
    // 在这里注册你的 suite 能力
  },
};
```

### 主工程注册属性面板（如数据加载）

`edhrSuitePlugin` 不再内置注册 `data-load.basic`，需在 **edhr 插件之后** 由主工程注册：

```ts
import { edhrSuitePlugin, registerPanelSchemas, type WordSuitePlugin } from '@gct-paas/word';
import DataLoadPanel from './panels/data-load/DataLoadPanel.vue';

const hostPanelPlugin: WordSuitePlugin = {
  key: 'host-panels',
  install() {
    registerPanelSchemas('edhr', {
      'data-load.basic': {
        key: 'data-load.basic',
        title: '数据加载',
        render: DataLoadPanel,
      },
    });
  },
};

setupPlatformAdapters({
  // ...
  plugins: [edhrSuitePlugin, hostPanelPlugin],
});
```

## 最佳实践

- `setupPlatformAdapters` 只在应用启动时调用一次，避免重复注册全局能力。
- 在 `createApp` 之后立即执行 `setupVueRuntime`，再调用 `mount`。
- `uploadFile`、`parseFile`、`getAppInfo` 建议提供稳定兜底实现，避免运行时空函数导致异常。
- 通过 `controller` 调用业务动作前，先判断 `controller.value` 是否已就绪。

## 常见问题

### 1) 组件渲染空白

- 检查是否已引入 `@gct-paas/word/style.css`
- 检查是否调用了 `setupVueRuntime({ app })`
- 检查容器是否有明确高度（例如 `height: 100vh`）

### 2) 数据加载失败

- 检查 `requestId`、`factoryType`、`modelKey` 是否匹配当前业务接口
- 检查 `interceptors` 与鉴权逻辑是否正确透传
- 检查 `getAppInfo`、`requestQuery` 是否包含业务必需上下文

### 3) 插件能力未生效

- 检查插件是否执行了 `install()`
- 检查是否在 `setupPlatformAdapters` 初始化阶段完成注册
- 检查 `suiteKey` 与已注册插件 `key` 是否一致

## 本仓库开发与发布

维护 `@gct-paas/word` 的分支策略、版本号与 npm 发布约定见仓库根目录文档：

[开发与发布流程](../../docs/development-and-release.md)

## License

MIT
