diff --git a/.github/workflows/deploy-cdn.yml b/.github/workflows/deploy-cdn.yml index 98df2d182f..9e7dd8bde2 100644 --- a/.github/workflows/deploy-cdn.yml +++ b/.github/workflows/deploy-cdn.yml @@ -9,12 +9,6 @@ on: default: true type: boolean -env: - HUAWEI_CLOUD_AK: ${{ secrets.HUAWEI_CLOUD_AK }} - HUAWEI_CLOUD_SK: ${{ secrets.HUAWEI_CLOUD_SK }} - HUAWEI_CLOUD_ENDPOINT: ${{ secrets.HUAWEI_CLOUD_ENDPOINT }} - HUAWEI_CLOUD_BUCKET: ${{ secrets.HUAWEI_CLOUD_BUCKET }} - jobs: check-secrets: runs-on: ubuntu-latest @@ -146,12 +140,12 @@ jobs: - name: Configure and Upload to OBS run: | - obsutil config -i=${{ env.HUAWEI_CLOUD_AK }} \ - -k=${{ env.HUAWEI_CLOUD_SK }} \ - -e=${{ env.HUAWEI_CLOUD_ENDPOINT }} + obsutil config -i=${{ secrets.HUAWEI_CLOUD_AK }} \ + -k=${{ secrets.HUAWEI_CLOUD_SK }} \ + -e=${{ secrets.HUAWEI_CLOUD_ENDPOINT }} # Upload to versioned path obsutil cp ./designer-demo/dist \ - obs://${{ env.HUAWEI_CLOUD_BUCKET }}/${{ needs.build.outputs.obs-path }} \ + obs://${{ secrets.HUAWEI_CLOUD_BUCKET }}/${{ needs.build.outputs.obs-path }} \ -r -f -flat # If is_latest_release is true, also upload to latest path @@ -160,9 +154,9 @@ jobs: find ./designer-demo/dist -type f \( -name "*.html" -o -name "*.js" -o -name "*.mjs" -o -name "*.css" \) \ -exec sed -i "s|${{ needs.build.outputs.cdn-base }}|${{ needs.build.outputs.cdn-base-latest }}|g" {} + obsutil cp ./designer-demo/dist \ - obs://${{ env.HUAWEI_CLOUD_BUCKET }}/${{ needs.build.outputs.obs-path-latest }} \ + obs://${{ secrets.HUAWEI_CLOUD_BUCKET }}/${{ needs.build.outputs.obs-path-latest }} \ -r -f -flat fi - echo "Uploaded to: obs://${{ env.HUAWEI_CLOUD_BUCKET }}/${{ needs.build.outputs.obs-path }}" + echo "Uploaded to: obs://${{ secrets.HUAWEI_CLOUD_BUCKET }}/${{ needs.build.outputs.obs-path }}" echo "CDN URL: https://res-static.opentiny.design/${{ needs.build.outputs.obs-path }}" diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..1598b97b6a --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,120 @@ +# TinyEngine — Repository Instructions for Coding Agents + +## Purpose and Scope + +This file is the canonical source of truth for repo-wide agent instructions. + +- Applies to the whole repository unless a closer `AGENTS.md` overrides it for a subtree. +- `CLAUDE.md` is a compatibility entrypoint that imports this file. Do not maintain a second independent copy of the same rules. +- Keep this file limited to repo-wide guidance. Package-specific implementation details belong in package-level instruction files. + +## Repository Snapshot + +- Monorepo: pnpm workspaces + lerna (independent versioning) +- Primary stack: Vue 3, Vite, JavaScript/TypeScript +- Package manager: `pnpm` only for interactive work in this repo +- Designer app: `designer-demo/` +- Local mock backend: `mockServer/` + +## Working Model + +- Inspect the affected package, its `package.json`, and the nearest instruction file before editing. +- Keep changes scoped. Do not normalize unrelated files or rename fixtures just for consistency. +- Prefer targeted package-level validation over whole-repo commands when possible. +- Treat `pnpm lint` and `pnpm format` as mutating commands, not read-only verification. +- Do not invoke `npm` or `yarn` directly for normal repo work. Existing package scripts may still shell out internally; leave that alone unless the task is specifically about package scripts. + +## Common Commands + +### Read-mostly commands + +```sh +pnpm install +pnpm dev +pnpm build:plugin +pnpm build:alpha +pnpm --filter @opentiny/tiny-engine-dsl-vue test:unit +``` + +### Mutating commands + +```sh +pnpm lint # ESLint with --fix +pnpm format # Prettier --write +``` + +Canonical script definitions live in: + +- `package.json` +- `packages/*/package.json` +- `.github/workflows/push-check.yml` +- `.github/workflows/Release.yml` + +## Verification Matrix + +Run the smallest sufficient verification for the change surface, then expand if the change is broad or risky. + +1. Docs-only changes: + No code verification required unless the docs change commands or workflow descriptions that should be checked against source files. +2. `packages/vue-generator/**`: + Run the affected testcase or `pnpm --filter @opentiny/tiny-engine-dsl-vue test:unit`. + If generator behavior changes, run the full `test:unit` suite before handoff and inspect any changed `expected/*.vue` files. +3. Published library packages under `packages/**`: + Run the package-local `test` script if one exists. + Run `pnpm build:plugin` when build output or published package behavior may be affected. +4. `designer-demo/**` or shared packages consumed by the demo: + Run `pnpm build:alpha`. +5. Cross-package build or release-facing changes: + Run `pnpm build:plugin` and `pnpm build:alpha`. +6. Config, workspace, CI, or release script changes: + Verify the directly affected command(s) after approval. + +## Approval Boundaries + +### Always OK + +- Read any source file +- Run targeted tests and builds +- Edit implementation files inside existing packages +- Add or update tests that match the scope of the change +- Update docs that reflect current repo behavior + +### Ask First + +- Changing workspace, lerna, pnpm, ESLint, Prettier, or TypeScript configuration +- Modifying CI workflows, release scripts, or publish flows +- Upgrading major dependencies or changing pinned overrides +- Reordering or adding/removing default vue-generator attribute hooks +- Large-scale edits to generated mappings or vendored patches + +When asking first, include: + +- what you want to change +- why the current rules or implementation are insufficient +- what verification you would run after approval + +### Never + +- Use `npm` or `yarn` directly for routine repo commands +- Skip hooks with `--no-verify` +- Hardcode versions for workspace packages +- Edit `patches/` without understanding the upstream issue and the patch purpose +- Rewrite generated expectations or snapshots without validating the new output first + +## Task-Specific Expectations + +- Bug fix: + Add or update a regression test when behavior changes. +- Refactor: + Preserve behavior and prove it with targeted verification. +- Snapshot or generated output change: + Explain why the output changed and list the affected fixture directories. +- Commit or PR work: + Only do it if asked. Use Conventional Commits and target `develop` unless the user specifies otherwise. + +## Gotchas + +- `pnpm install` is enforced by `preinstall`; npm and yarn are rejected for direct repo usage. +- `pnpm lint` writes fixes. Use it deliberately. +- CI relies on `build:plugin` and `build:alpha`, not only lint or unit tests. +- Test directories such as `test/`, `expected/`, and `output/` are not always linted; do not treat lint success as fixture validation. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000000..36fb0d736b --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,7 @@ +# TinyEngine — Claude Code Entry + +This file is intentionally thin. The canonical repo-wide instructions live in `AGENTS.md`. + +@./AGENTS.md + +When working inside a subtree that has its own `CLAUDE.md`, follow the closer file as an extension of these repo-wide rules. diff --git a/designer-demo/engine.config.js b/designer-demo/engine.config.js index 5f9e5a703d..b773842f19 100644 --- a/designer-demo/engine.config.js +++ b/designer-demo/engine.config.js @@ -5,5 +5,7 @@ export default { scripts: [], styles: [], // 是否开启 TailWindCSS 特性 - enableTailwindCSS: true + enableTailwindCSS: true, + // 是否开启 使用结构化CSS 特性 + enableStructuredCss: false } diff --git a/designer-demo/env/.env.development b/designer-demo/env/.env.development index 25a3fd1e9d..3d28957eba 100644 --- a/designer-demo/env/.env.development +++ b/designer-demo/env/.env.development @@ -5,4 +5,4 @@ VITE_CDN_DOMAIN=https://registry.npmmirror.com # 使用npmmirror的cdn 时,需要声明 VITE_CDN_TYPE=npmmirror VITE_CDN_TYPE=npmmirror # request data via alpha service -# VITE_ORIGIN= +# VITE_ORIGIN= \ No newline at end of file diff --git a/designer-demo/package.json b/designer-demo/package.json index e926a0d4cb..abb9f337d0 100644 --- a/designer-demo/package.json +++ b/designer-demo/package.json @@ -1,7 +1,7 @@ { "name": "designer-demo", "private": true, - "version": "2.10.0-rc.0", + "version": "2.10.0", "type": "module", "scripts": { "dev": "cross-env vite", diff --git a/designer-demo/public/mock/bundle.json b/designer-demo/public/mock/bundle.json index 0495b36964..361479b2b1 100644 --- a/designer-demo/public/mock/bundle.json +++ b/designer-demo/public/mock/bundle.json @@ -3,6 +3,1045 @@ "framework": "Vue", "materials": { "components": [ + { + "version": "3.22.0", + "name": { + "zh_CN": "动作菜单" + }, + "component": "TinyActionMenu", + "icon": "dropdown", + "description": "动作菜单", + "docUrl": "", + "screenshot": "", + "tags": "", + "keywords": "", + "devMode": "proCode", + "npm": { + "package": "@opentiny/vue", + "exportName": "TinyActionMenu", + "destructuring": true + }, + "group": "component", + "category": "动作菜单", + "priority": 2, + "schema": { + "properties": [ + { + "name": "0", + "label": { + "zh_CN": "基础属性" + }, + "content": [ + { + "cols": 12, + "type": "object", + "label": { + "text": { + "zh_CN": "绑定值" + } + }, + "widget": { + "props": { + "height": 150, + "language": "json" + }, + "component": "CodeConfigurator" + }, + "disabled": false, + "property": "options", + "readOnly": false, + "required": true, + "description": { + "zh_CN": "菜单项列表的数据" + }, + "defaultValue": null, + "labelPosition": "left" + }, + { + "cols": 12, + "type": "number", + "label": { + "text": { + "zh_CN": "最大显示数量" + } + }, + "widget": { + "props": { + "step": 2 + }, + "component": "NumberConfigurator" + }, + "disabled": false, + "property": "maxShowNum", + "readOnly": false, + "required": false, + "description": "最多显示菜单按钮的个数,其他菜单在下拉弹框显示", + "defaultValue": 2, + "labelPosition": "left" + }, + { + "cols": 12, + "type": "string", + "label": { + "text": { + "zh_CN": "按钮模式" + } + }, + "widget": { + "props": { + "options": [ + { + "label": "default", + "value": "default" + }, + { + "label": "card", + "value": "card" + } + ] + }, + "component": "SelectConfigurator" + }, + "disabled": false, + "property": "mode", + "readOnly": false, + "required": false, + "description": "菜单按钮模式", + "defaultValue": "default", + "labelPosition": "left" + }, + { + "cols": 12, + "type": "string", + "label": { + "text": { + "zh_CN": "下拉按钮文本" + } + }, + "widget": { + "props": { + "placeholder": "请输入..." + }, + "component": "InputConfigurator" + }, + "disabled": false, + "property": "moreText", + "readOnly": false, + "required": false, + "description": "下拉按钮文本", + "defaultValue": "更多", + "labelPosition": "left" + }, + { + "cols": 12, + "type": "string", + "label": { + "text": { + "zh_CN": "二级下拉面板的显示位置" + } + }, + "widget": { + "props": { + "options": [ + { + "label": "bottom-start", + "value": "bottom-start" + }, + { + "label": "bottom-end", + "value": "bottom-end" + } + ] + }, + "component": "SelectConfigurator" + }, + "disabled": false, + "property": "placement", + "readOnly": false, + "required": false, + "description": "二级下拉面板的显示位置", + "defaultValue": "bottom-end", + "labelPosition": "top" + }, + { + "cols": 12, + "type": "boolean", + "label": { + "text": { + "zh_CN": "show-icon" + } + }, + "widget": { + "props": {}, + "component": "CheckBoxConfigurator" + }, + "disabled": false, + "property": "showIcon", + "readOnly": false, + "required": false, + "description": "是否显示下拉触发源图标", + "defaultValue": true, + "labelPosition": "left" + }, + { + "cols": 12, + "type": "string", + "label": { + "text": { + "zh_CN": "text-field" + } + }, + "widget": { + "props": { + "placeholder": "请输入..." + }, + "component": "InputConfigurator" + }, + "disabled": false, + "property": "textField", + "readOnly": false, + "required": false, + "description": "菜单按钮文本的键值", + "defaultValue": "label", + "labelPosition": "left" + } + ], + "description": { + "zh_CN": "组件核心功能相关的配置,包括 name、size、type 等核心属性" + } + }, + { + "name": "1", + "label": { + "zh_CN": "样式属性" + }, + "content": [ + { + "cols": 12, + "type": "string", + "label": { + "text": { + "zh_CN": "按钮间距" + } + }, + "widget": { + "props": { + "placeholder": "请输入..." + }, + "component": "InputConfigurator" + }, + "disabled": false, + "property": "spacing", + "readOnly": false, + "required": false, + "description": "菜单按钮之间的间距", + "defaultValue": "5px", + "labelPosition": "left" + } + ], + "description": { + "zh_CN": "组件外观、颜色、尺寸相关的配置,包括 width、height、backgroundColor、color 等与视觉呈现相关的属性" + } + } + ], + "events": { + "onItemClick": { + "type": "event", + "label": { + "zh_CN": "菜单项点击" + }, + "description": { + "zh_CN": "监听点击菜单项事件" + }, + "defaultValue": "", + "functionInfo": { + "params": [ + { + "name": "data", + "type": "IItemClickParam", + "description": { + "zh_CN": "点击的菜单项参数数据" + }, + "defaultValue": "" + } + ], + "returns": { + "type": "", + "description": { + "zh_CN": "事件返回值的描述文字" + }, + "defaultValue": "" + } + } + }, + "onButtonClick": { + "type": "event", + "label": { + "zh_CN": "左侧按钮点击" + }, + "description": { + "zh_CN": "监听左侧按钮点击事件,仅 split-button 为 true 时生效" + }, + "defaultValue": "", + "functionInfo": { + "params": [], + "returns": { + "type": "", + "description": { + "zh_CN": "事件返回值的描述文字" + }, + "defaultValue": "" + } + } + }, + "onVisibleChange": { + "type": "event", + "label": { + "zh_CN": "显隐状态变化" + }, + "description": { + "zh_CN": "监听下拉框的显示或隐藏状态" + }, + "defaultValue": "", + "functionInfo": { + "params": [ + { + "name": "status", + "type": "boolean", + "description": { + "zh_CN": "下拉框的显示或隐藏状态" + }, + "defaultValue": "" + } + ], + "returns": { + "type": "", + "description": { + "zh_CN": "事件返回值的描述文字" + }, + "defaultValue": "" + } + } + } + }, + "slots": { + "default": { + "label": { + "zh_CN": "默认内容" + }, + "description": { + "zh_CN": "自定义触发源文本区域。 注意: 必须是一个元素或者或者组件" + } + }, + "dropdown": { + "label": { + "zh_CN": "下拉列表" + }, + "description": { + "zh_CN": "自定义下拉列表区域,通常使用 tiny-dropdown-menu 组件" + } + } + } + }, + "configure": { + "loop": true, + "condition": true, + "styles": true, + "isContainer": false, + "isModal": false, + "nestingRule": { + "childWhitelist": "", + "parentWhitelist": "", + "descendantBlacklist": "", + "ancestorWhitelist": "" + }, + "isNullNode": false, + "isLayout": false, + "rootSelector": "", + "shortcuts": { + "properties": [] + }, + "contextMenu": { + "actions": [ + "create symbol" + ], + "disable": [ + "copy", + "remove" + ] + } + } + }, + { + "version": "3.22.0", + "name": { + "zh_CN": "下拉菜单" + }, + "component": "TinyDropdown", + "icon": "dropdown", + "description": "下拉菜单", + "docUrl": "", + "screenshot": "", + "tags": "", + "keywords": "", + "devMode": "proCode", + "npm": { + "package": "@opentiny/vue", + "exportName": "TinyDropdown", + "destructuring": true + }, + "group": "component", + "category": "下拉菜单", + "priority": 2, + "schema": { + "properties": [ + { + "name": "0", + "label": { + "zh_CN": "基础属性" + }, + "content": [ + { + "cols": 12, + "type": "string", + "label": { + "text": { + "zh_CN": "尺寸" + } + }, + "widget": { + "props": { + "options": [ + { + "label": "medium", + "value": "medium" + }, + { + "label": "small", + "value": "small" + }, + { + "label": "mini", + "value": "mini" + } + ] + }, + "component": "SelectConfigurator" + }, + "disabled": false, + "property": "size", + "readOnly": false, + "required": false, + "description": "菜单尺寸。注意:只在 split-button为 true 的情况下生效", + "defaultValue": null, + "labelPosition": "left" + }, + { + "cols": 12, + "type": "boolean", + "label": { + "text": { + "zh_CN": "分割按钮" + } + }, + "widget": { + "props": {}, + "component": "CheckBoxConfigurator" + }, + "disabled": false, + "property": "split-button", + "readOnly": false, + "required": false, + "description": "下拉触发元素呈现为按钮", + "defaultValue": false, + "labelPosition": "left" + }, + { + "cols": 12, + "type": "ibuttontype", + "label": { + "text": { + "zh_CN": "按钮类型" + } + }, + "widget": { + "props": { + "placeholder": "请输入..." + }, + "component": "InputConfigurator" + }, + "disabled": false, + "property": "type", + "readOnly": false, + "required": false, + "description": "按钮类型。注意:只在 split-button 为 true 的情况下有效", + "defaultValue": null, + "labelPosition": "left" + }, + { + "cols": 12, + "type": "string", + "label": { + "text": { + "zh_CN": "触发方式" + } + }, + "widget": { + "props": { + "options": [ + { + "label": "hover", + "value": "hover" + }, + { + "label": "click", + "value": "click" + }, + { + "label": "contextmenu", + "value": "contextmenu" + } + ] + }, + "component": "SelectConfigurator" + }, + "disabled": false, + "property": "trigger", + "readOnly": false, + "required": false, + "description": "触发下拉的方式", + "defaultValue": "hover", + "labelPosition": "left" + }, + { + "cols": 12, + "type": "iplacementtype", + "label": { + "text": { + "zh_CN": "弹出位置" + } + }, + "widget": { + "props": { + "placeholder": "请输入..." + }, + "component": "InputConfigurator" + }, + "disabled": false, + "property": "placement", + "readOnly": false, + "required": false, + "description": "菜单弹出位置", + "defaultValue": "bottom-end", + "labelPosition": "left" + }, + { + "cols": 12, + "type": "boolean", + "label": { + "text": { + "zh_CN": "显隐状态" + } + }, + "widget": { + "props": {}, + "component": "CheckBoxConfigurator" + }, + "disabled": false, + "property": "visible", + "readOnly": false, + "required": false, + "description": "手动控制下拉弹框显隐,优先级高于trigger", + "defaultValue": false, + "labelPosition": "left" + } + ], + "description": { + "zh_CN": "组件核心功能相关的配置,包括 name、size、type 等核心属性" + } + }, + { + "name": "1", + "label": { + "zh_CN": "样式属性" + }, + "content": [ + { + "cols": 12, + "type": "string", + "label": { + "text": { + "zh_CN": "标题" + } + }, + "widget": { + "props": { + "placeholder": "请输入..." + }, + "component": "InputConfigurator" + }, + "disabled": false, + "property": "title", + "readOnly": false, + "required": false, + "description": "自定义触发源的文本", + "defaultValue": "下拉菜单", + "labelPosition": "left" + }, + { + "cols": 12, + "type": "boolean", + "label": { + "text": { + "zh_CN": "显示图标" + } + }, + "widget": { + "props": {}, + "component": "SwitchConfigurator" + }, + "disabled": false, + "property": "show-icon", + "readOnly": false, + "required": false, + "description": "是否显示下拉触发源图标", + "defaultValue": true, + "labelPosition": "left" + }, + { + "cols": 12, + "type": "component", + "label": { + "text": { + "zh_CN": "图标" + } + }, + "widget": { + "props": { + "placeholder": "请输入图标名称" + }, + "component": "InputConfigurator" + }, + "disabled": false, + "property": "suffix-icon", + "readOnly": false, + "required": false, + "description": "下拉触发源图标", + "defaultValue": null, + "labelPosition": "left" + }, + { + "cols": 12, + "type": "boolean", + "label": { + "text": { + "zh_CN": "继承宽度" + } + }, + "widget": { + "props": {}, + "component": "CheckBoxConfigurator" + }, + "disabled": false, + "property": "inherit-width", + "readOnly": false, + "required": false, + "description": "下拉弹框的最小宽度是否继承触发源的宽度,默认不继承", + "defaultValue": false, + "labelPosition": "left" + }, + { + "cols": 12, + "type": "boolean", + "label": { + "text": { + "zh_CN": "显示箭头" + } + }, + "widget": { + "props": {}, + "component": "CheckBoxConfigurator" + }, + "disabled": false, + "property": "visible-arrow", + "readOnly": false, + "required": false, + "description": "下拉弹框是否显示箭头,默认不显示", + "defaultValue": false, + "labelPosition": "left" + }, + { + "cols": 12, + "type": "string", + "label": { + "text": { + "zh_CN": "弹框类名" + } + }, + "widget": { + "props": { + "placeholder": "请输入..." + }, + "component": "InputConfigurator" + }, + "disabled": false, + "property": "popper-class", + "readOnly": false, + "required": false, + "description": "下拉弹框的类名,用于自定义样式", + "defaultValue": null, + "labelPosition": "left" + } + ], + "description": { + "zh_CN": "组件外观、颜色、尺寸相关的配置,包括 width、height、backgroundColor、color 等与视觉呈现相关的属性" + } + }, + { + "name": "2", + "label": { + "zh_CN": "行为属性" + }, + "content": [ + { + "cols": 12, + "type": "boolean", + "label": { + "text": { + "zh_CN": "禁用" + } + }, + "widget": { + "props": {}, + "component": "CheckBoxConfigurator" + }, + "disabled": false, + "property": "disabled", + "readOnly": false, + "required": false, + "description": "是否禁用", + "defaultValue": false, + "labelPosition": "left" + }, + { + "cols": 12, + "type": "boolean", + "label": { + "text": { + "zh_CN": "点击收起" + } + }, + "widget": { + "props": {}, + "component": "CheckBoxConfigurator" + }, + "disabled": false, + "property": "hide-on-click", + "readOnly": false, + "required": false, + "description": "点击菜单项后是否收起菜单。默认点击后收起", + "defaultValue": true, + "labelPosition": "left" + }, + { + "cols": 12, + "type": "number", + "label": { + "text": { + "zh_CN": "收起延时" + } + }, + "widget": { + "props": { + "step": 1 + }, + "component": "NumberConfigurator" + }, + "disabled": false, + "property": "hide-timeout", + "readOnly": false, + "required": false, + "description": "延时多久收起下拉菜单,单位毫秒。注意:仅在 trigger 为 hover 时有效", + "defaultValue": 150, + "labelPosition": "left" + }, + { + "cols": 12, + "type": "number", + "label": { + "text": { + "zh_CN": "展开延时" + } + }, + "widget": { + "props": { + "step": 1 + }, + "component": "NumberConfigurator" + }, + "disabled": false, + "property": "show-timeout", + "readOnly": false, + "required": false, + "description": "延时多久展开下拉菜单,单位毫秒。注意:仅在 trigger 为 hover 时有效", + "defaultValue": 250, + "labelPosition": "left" + }, + { + "cols": 12, + "type": "number", + "label": { + "text": { + "zh_CN": "Tab索引" + } + }, + "widget": { + "props": { + "step": 1 + }, + "component": "NumberConfigurator" + }, + "disabled": false, + "property": "tabindex", + "readOnly": false, + "required": false, + "description": "初始化触发元素的原生属性 tabindex", + "defaultValue": 0, + "labelPosition": "left" + } + ], + "description": { + "zh_CN": "组件交互、事件、状态相关的配置,包括 disabled、loading、onClick 等与用户操作和状态相关的属性" + } + }, + { + "name": "3", + "label": { + "zh_CN": "高级属性" + }, + "content": [ + { + "cols": 12, + "type": "boolean", + "label": { + "text": { + "zh_CN": "懒加载" + } + }, + "widget": { + "props": {}, + "component": "CheckBoxConfigurator" + }, + "disabled": false, + "property": "lazy-show-popper", + "readOnly": false, + "required": false, + "description": "是否懒加载下拉菜单及内部的项,以优化性能,默认初始全加载菜单及内部项。", + "defaultValue": false, + "labelPosition": "left" + }, + { + "cols": 12, + "type": "imenuoption", + "label": { + "text": { + "zh_CN": "菜单配置" + } + }, + "widget": { + "props": { + "height": 150, + "language": "json" + }, + "component": "CodeConfigurator" + }, + "disabled": false, + "property": "menu-options", + "readOnly": false, + "required": false, + "description": "配置式且只使用 tiny-dropdown 组件时使用", + "defaultValue": "{ options:[], textField:\"label\", popperClass:\"\", placement:\"bottom-end\" }", + "labelPosition": "left" + }, + { + "cols": 12, + "type": "iitemdata[]", + "label": { + "text": { + "zh_CN": "菜单项配置" + } + }, + "widget": { + "props": { + "height": 150, + "language": "json" + }, + "component": "CodeConfigurator" + }, + "disabled": false, + "property": "options", + "readOnly": false, + "required": false, + "description": "通过配置式设置菜单项的属性", + "defaultValue": "[]", + "labelPosition": "left" + }, + { + "cols": 12, + "type": "string", + "label": { + "text": { + "zh_CN": "文本字段" + } + }, + "widget": { + "props": { + "placeholder": "请输入..." + }, + "component": "InputConfigurator" + }, + "disabled": false, + "property": "text-field", + "readOnly": false, + "required": false, + "description": "菜单项文本的字段,结合 options 属性使用", + "defaultValue": "label", + "labelPosition": "left" + } + ], + "description": { + "zh_CN": "组件可选的专业配置项,包括复杂对象配置、高级功能选项等不常用的特殊配置" + } + } + ], + "events": { + "onItemClick": { + "type": "event", + "label": { + "zh_CN": "菜单项点击" + }, + "description": { + "zh_CN": "监听点击菜单项事件" + }, + "defaultValue": "", + "functionInfo": { + "params": [ + { + "name": "data", + "type": "IItemClickParam", + "description": { + "zh_CN": "点击的菜单项参数数据" + }, + "defaultValue": "" + } + ], + "returns": { + "type": "", + "description": { + "zh_CN": "事件返回值的描述文字" + }, + "defaultValue": "" + } + } + }, + "onButtonClick": { + "type": "event", + "label": { + "zh_CN": "左侧按钮点击" + }, + "description": { + "zh_CN": "监听左侧按钮点击事件,仅 split-button 为 true 时生效" + }, + "defaultValue": "", + "functionInfo": { + "params": [], + "returns": { + "type": "", + "description": { + "zh_CN": "事件返回值的描述文字" + }, + "defaultValue": "" + } + } + }, + "onVisibleChange": { + "type": "event", + "label": { + "zh_CN": "显隐状态变化" + }, + "description": { + "zh_CN": "监听下拉框的显示或隐藏状态" + }, + "defaultValue": "", + "functionInfo": { + "params": [ + { + "name": "status", + "type": "boolean", + "description": { + "zh_CN": "下拉框的显示或隐藏状态" + }, + "defaultValue": "" + } + ], + "returns": { + "type": "", + "description": { + "zh_CN": "事件返回值的描述文字" + }, + "defaultValue": "" + } + } + } + }, + "slots": { + "default": { + "label": { + "zh_CN": "默认内容" + }, + "description": { + "zh_CN": "自定义触发源文本区域。 注意: 必须是一个元素或者或者组件" + } + }, + "dropdown": { + "label": { + "zh_CN": "下拉列表" + }, + "description": { + "zh_CN": "自定义下拉列表区域,通常使用 tiny-dropdown-menu 组件" + } + } + } + }, + "configure": { + "loop": true, + "condition": true, + "styles": true, + "isContainer": false, + "isModal": false, + "nestingRule": { + "childWhitelist": "", + "parentWhitelist": "", + "descendantBlacklist": "", + "ancestorWhitelist": "" + }, + "isNullNode": false, + "isLayout": false, + "rootSelector": "", + "shortcuts": { + "properties": [] + }, + "contextMenu": { + "actions": [ + "create symbol" + ], + "disable": [ + "copy", + "remove" + ] + } + } + }, { "version": "3.22.0", "name": { @@ -26232,6 +27271,76 @@ "node-key": "id" } } + }, + { + "name": { + "zh_CN": "下拉菜单" + }, + "icon": "dropdown", + "screenshot": "", + "snippetName": "TinyDropdown", + "schema": { + "componentName": "TinyDropdown", + "props": { + "menu-options": { + "options": [ + { + "name": "老友粉", + "disabled": true + }, + { + "name": "狮子头", + "divided": true + }, + { + "name": "黄金糕", + "divided": true + } + ], + "textField": "name" + } + } + } + }, + { + "name": { + "zh_CN": "动作菜单" + }, + "icon": "dropdown", + "screenshot": "", + "snippetName": "TinyActionMenu", + "schema": { + "componentName": "TinyActionMenu", + "props": { + "options": [ + { + "label": "远程登录" + }, + { + "label": "开机" + }, + { + "label": "关机" + }, + { + "label": "重启", + "divided": true + }, + { + "label": "网络设置", + "children": [ + { + "label": "更改安全组" + }, + { + "label": "切换 VPC", + "divided": true + } + ] + } + ] + } + } } ] }, diff --git a/docs/README.md b/docs/README.md index ca958736c8..bd9ebe4da1 100644 --- a/docs/README.md +++ b/docs/README.md @@ -95,7 +95,6 @@ - [应用工具类管理](./api/backend-api/app-utility-management.md) - [区块管理](./api/backend-api/block-management-api.md) - [数据源管理](./api/backend-api/data-source-management.md) - - [DSL代码生成](./api/backend-api/dsl-code-generation.md) - [物料中心](./api/backend-api/material-center.md) - [页面管理](./api/backend-api/page-management-api.md) - [APP服务](./api/backend-api/app-services.md) diff --git a/docs/api/backend-api/dsl-code-generation.md b/docs/api/backend-api/dsl-code-generation.md deleted file mode 100644 index 1dff789d74..0000000000 --- a/docs/api/backend-api/dsl-code-generation.md +++ /dev/null @@ -1,106 +0,0 @@ -# DSL代码生成 - -## generateCode - - - -### 基本信息 - -**Path:** /generateCode - -**Method:** GET - -**接口描述:** - -

作为npm包使用generateCode方法生成代码示例:

- -
const path = require('path')
-const fs = require('fs')
-const { generateCode } = require('@opentiny/tiny-engine-dsl-ng-tiny/lib/generate-code.js')
-
-
-
-const result = generateCode({ pageInfo, blocksData })
-result.forEach((item) => fs.writeFileSync(`dist/${item.filePath}/${item.panelName}`, item.panelValue))
-
- -

输入示例: { pageInfo, blocksData };

- -
// pageInfo为页面的schema信息, 
-// pageInfo: { schema, name });
-{
-  name: 'page1',
-  schema: {
-     // 页面schema
-  }
-}
-
-
-// blocksData为页面引用的区块的schema数据
-// blocksData: Array<{ label, content }>
-[
-  {
-    label: 'image-title',
-    content: {
-      // 区块的schema
-    }
-  },
-  {
-    // 其他区块...
-  }
-]
-
- -

输出示例:

-
[
-  {
-    "panelName": "page1.component.html",  // 文件名
-    "panelValue": "xxx",    // 生成代码的内容
-    "panelType": "html",     // 生成代码的文件类型:html、css、ts
-    "prettierOpt": { "parser": "html", "tabWidth": 2, "printWidth": 120 }, // prettier格式化选项
-    "type": "page",  // 生成代码类型:page、block、service
-    "filePath": "pages/page1"   // 生成代码文件的相对目录路径
-  },
-  {
-    "panelName": "page1.component.ts",
-    "panelValue": "xxx",
-    "panelType": "ts",
-    "prettierOpt": { "parser": "typescript", "tabWidth": 2, "printWidth": 120 },
-    "type": "page",
-    "filePath": "pages/page1"
-  },
-  {
-    "panelName": "block1.component.ts",
-    "type": "block",
-    "panelType": "ts",
-    "prettierOpt": { "parser": "typescript", "tabWidth": 2, "printWidth": 120 },
-    "filePath": "blocks/block1",
-    "panelValue": "xxx"
-  },
-  {
-    "panelName": "fetch.service.ts",
-    "panelType": "ts",
-    "prettierOpt": { "parser": "typescript", "tabWidth": 2, "printWidth": 120 },
-    "type": "service",
-    "filePath": "service",
-    "panelValue": "xxx"
-  },
-  // ...
-]
-
- - - -### 请求参数 - -### 返回数据 - - - - - - - - -
名称类型是否必须默认值备注其他信息
object []非必须

item 类型: object

├─ panelNamestring必须文件名
├─ panelValuestring必须文件文本
├─ panelTypestring必须代码类型
├─ prettierOptobject必须代码美化选项
├─ parserstring非必须指定要使用的解析器
├─ tabWidthnumber非必须指定使用几个空格来表示一个制表符(Tab)
├─ printWidthnumber非必须指定每行代码的最大列数
├─ typestring必须代码类型
├─ filePathstring必须文件路径
- diff --git a/docs/catalog.json b/docs/catalog.json index bea1934510..97e64f383d 100644 --- a/docs/catalog.json +++ b/docs/catalog.json @@ -8,23 +8,56 @@ "title": "新手指引", "name": "getting-started", "articles": [ - { "title": "简介", "name": "introduction.md" }, - { "title": "快速上手", "name": "quick-start.md" } + { + "title": "简介", + "name": "introduction.md" + }, + { + "title": "快速上手", + "name": "quick-start.md" + } ] }, { "title": "基础功能", "name": "basic-features", "articles": [ - { "title": "设计器界面模块简介", "name": "designer-ui-modules.md" }, - { "title": "设计前端应用流程", "name": "frontend-application-flow.md" }, - { "title": "页面管理", "name": "page-management.md" }, - { "title": "使用组件", "name": "using-components.md" }, - { "title": "样式设置", "name": "style-settings.md" }, - { "title": "使用状态管理和变量绑定", "name": "state-management-and-variable-binding.md" }, - { "title": "行内样式绑定状态变量", "name": "inline-style-variable-binding.md" }, - { "title": "查看大纲树", "name": "outline-tree.md" }, - { "title": "国际化", "name": "internationalization.md" }, + { + "title": "设计器界面模块简介", + "name": "designer-ui-modules.md" + }, + { + "title": "设计前端应用流程", + "name": "frontend-application-flow.md" + }, + { + "title": "页面管理", + "name": "page-management.md" + }, + { + "title": "使用组件", + "name": "using-components.md" + }, + { + "title": "样式设置", + "name": "style-settings.md" + }, + { + "title": "使用状态管理和变量绑定", + "name": "state-management-and-variable-binding.md" + }, + { + "title": "行内样式绑定状态变量", + "name": "inline-style-variable-binding.md" + }, + { + "title": "查看大纲树", + "name": "outline-tree.md" + }, + { + "title": "国际化", + "name": "internationalization.md" + }, { "title": "资源管理", "name": "resources-management.md" @@ -39,40 +72,94 @@ "title": "进阶功能", "name": "advanced-features", "articles": [ - { "title": "区块管理", "name": "block-management.md" }, - { "title": "使用JS面板和事件绑定", "name": "js-panel-and-event-binding.md" }, + { + "title": "区块管理", + "name": "block-management.md" + }, + { + "title": "使用JS面板和事件绑定", + "name": "js-panel-and-event-binding.md" + }, { "title": "使用工具类方法 utils", "name": "using-utils-methods.md" }, - { "title": "高级面板设置", "name": "advanced-panel-settings.md" }, - { "title": "如何使用插槽", "name": "how-to-use-slots.md" }, - { "title": "循环渲染", "name": "loop-rendering.md" }, - { "title": "条件渲染", "name": "conditional-rendering.md" }, - { "title": "新版AI插件使用", "name": "new-ai-plugin-usage.md" }, - { "title": "数据源和Collection—远程字段", "name": "data-source-and-collection-remote-fields.md" }, - { "title": "数据源和Collection—mock数据", "name": "data-source-and-collection-mock-data.md" }, - { "title": "数据源和Collection—使用数据源", "name": "data-source-and-collection-usage.md" }, + { + "title": "高级面板设置", + "name": "advanced-panel-settings.md" + }, + { + "title": "如何使用插槽", + "name": "how-to-use-slots.md" + }, + { + "title": "循环渲染", + "name": "loop-rendering.md" + }, + { + "title": "条件渲染", + "name": "conditional-rendering.md" + }, + { + "title": "新版AI插件使用", + "name": "new-ai-plugin-usage.md" + }, + { + "title": "数据源和Collection—远程字段", + "name": "data-source-and-collection-remote-fields.md" + }, + { + "title": "数据源和Collection—mock数据", + "name": "data-source-and-collection-mock-data.md" + }, + { + "title": "数据源和Collection—使用数据源", + "name": "data-source-and-collection-usage.md" + }, { "title": "路由能力", "name": "route-capabilities", "articles": [ - { "title": "页面支持嵌套路由", "name": "page-support-nested-route.md" }, - { "title": "路由bar一键清除预览页面路径", "name": "route-bar-clear-preview-page.md" }, - { "title": "路由bar高亮显示预览页面路径", "name": "route-bar-current-page-highlight.md" }, - { "title": "RouterView组件支持预览子界面", "name": "route-view-support-preview-subpage.md" } + { + "title": "页面支持嵌套路由", + "name": "page-support-nested-route.md" + }, + { + "title": "路由bar一键清除预览页面路径", + "name": "route-bar-clear-preview-page.md" + }, + { + "title": "路由bar高亮显示预览页面路径", + "name": "route-bar-current-page-highlight.md" + }, + { + "title": "RouterView组件支持预览子界面", + "name": "route-view-support-preview-subpage.md" + } ] }, - { "title": "主题切换功能", "name": "theme-switch.md" }, - { "title": "画布快捷操作", "name": "canvas-shortcuts.md" } + { + "title": "主题切换功能", + "name": "theme-switch.md" + }, + { + "title": "画布快捷操作", + "name": "canvas-shortcuts.md" + } ] }, { "title": "教程", "name": "tutorials", "articles": [ - { "title": "从零搭建一个页面", "name": "build-a-page-from-scratch.md" }, - { "title": "第一期2023.10.27", "name": "issue-1-2023.10.27.md" } + { + "title": "从零搭建一个页面", + "name": "build-a-page-from-scratch.md" + }, + { + "title": "第一期2023.10.27", + "name": "issue-1-2023.10.27.md" + } ] } ] @@ -85,18 +172,32 @@ "title": "开始", "name": "development-getting-started", "articles": [ - { "title": "简介", "name": "dev-intro.md" }, - { "title": "快速上手", "name": "dev-quick-start.md" }, - { "title": "前后端启动联调(Java服务端)", "name": "debugging-of-java-backend.md" } + { + "title": "简介", + "name": "dev-intro.md" + }, + { + "title": "快速上手", + "name": "dev-quick-start.md" + }, + { + "title": "前后端启动联调(Java服务端)", + "name": "debugging-of-java-backend.md" + } ] }, - { "title": "更新日志", "name": "changelog", "articles": [ - { "title": "更新日志", "name": "changelog.md" }, - { "title": "v2.7升级指南", "name": "v2.7-upgrade-guide.md" } + { + "title": "更新日志", + "name": "changelog.md" + }, + { + "title": "v2.7升级指南", + "name": "v2.7-upgrade-guide.md" + } ] }, { @@ -107,84 +208,212 @@ "title": "前端及Java服务端docker部署", "name": "front-backend-docker-deployment.md" }, - { "title": "Java服务端部署", "name": "server-deployment-solution-java.md" }, - { "title": "Node.js服务端部署", "name": "server-deployment-solution.md" }, - { "title": "区块发布方案(Node.js服务端)", "name": "block-release-solution.md" }, - { "title": "区块局域网发布方案(Node.js服务端)", "name": "block-lan-release-solution.md" }, - { "title": "设计器中引入第三方组件库", "name": "third-party-library-in-designer.md" }, - { "title": "物料同步方案", "name": "material-sync-solution.md" }, - { "title": "本地化CDN方案", "name": "import-map-local.md" }, - { "title": "全新区块构建方案", "name": "block-construction-solution.md" }, - { "title": "全新画布通信方案", "name": "canvas-communication-solution.md" } + { + "title": "Java服务端部署", + "name": "server-deployment-solution-java.md" + }, + { + "title": "Node.js服务端部署", + "name": "server-deployment-solution.md" + }, + { + "title": "区块发布方案(Node.js服务端)", + "name": "block-release-solution.md" + }, + { + "title": "区块局域网发布方案(Node.js服务端)", + "name": "block-lan-release-solution.md" + }, + { + "title": "设计器中引入第三方组件库", + "name": "third-party-library-in-designer.md" + }, + { + "title": "物料同步方案", + "name": "material-sync-solution.md" + }, + { + "title": "本地化CDN方案", + "name": "import-map-local.md" + }, + { + "title": "全新区块构建方案", + "name": "block-construction-solution.md" + }, + { + "title": "全新画布通信方案", + "name": "canvas-communication-solution.md" + } ] }, { "title": "扩展能力介绍", "name": "extension-capabilities-overview", "articles": [ - { "title": "新架构介绍", "name": "new-architecture.md" }, - { "title": "注册表", "name": "registry.md" }, - { "title": "注册表(新版)", "name": "new-registry.md" }, - { "title": "注册表高级特性", "name": "new-registry-advanced.md" }, - { "title": "元服务和元应用", "name": "meta-services-and-meta-apps.md" } + { + "title": "新架构介绍", + "name": "new-architecture.md" + }, + { + "title": "注册表", + "name": "registry.md" + }, + { + "title": "注册表(新版)", + "name": "new-registry.md" + }, + { + "title": "注册表高级特性", + "name": "new-registry-advanced.md" + }, + { + "title": "元服务和元应用", + "name": "meta-services-and-meta-apps.md" + } ] }, { "title": "扩展能力使用教程", "name": "extension-capabilities-tutorial", "articles": [ - { "title": "如何开发插件", "name": "how-to-develop-plugins.md" }, + { + "title": "如何开发插件", + "name": "how-to-develop-plugins.md" + }, { "title": "出码功能", "name": "code-output-function", "articles": [ - { "title": "出码功能简介与使用", "name": "code-output-overview-and-usage.md" }, - { "title": "如何自定义出码", "name": "how-to-customize-code-output.md" }, - { "title": "如何自定义出码插件", "name": "how-to-customize-code-output-plugins.md" }, - { "title": "自定义页面出码插件", "name": "custom-page-code-output-plugin.md" }, - { "title": "官方出码能力API", "name": "official-code-output-api.md" } + { + "title": "出码功能简介与使用", + "name": "code-output-overview-and-usage.md" + }, + { + "title": "如何自定义出码", + "name": "how-to-customize-code-output.md" + }, + { + "title": "如何自定义出码插件", + "name": "how-to-customize-code-output-plugins.md" + }, + { + "title": "自定义页面出码插件", + "name": "custom-page-code-output-plugin.md" + }, + { + "title": "官方出码能力API", + "name": "official-code-output-api.md" + } ] }, - { "title": "定制插件UI", "name": "customize-plugin-ui.md" }, - { "title": "定制元服务逻辑", "name": "customize-meta-service-logic.md" }, - { "title": "开发设置器组件", "name": "develop-configurator-components.md" }, - { "title": "AI插件使用前配置", "name": "ai-plugin-configuration.md" }, - { "title": "如何自定义主题", "name": "how-to-custom-theme.md" } + { + "title": "定制插件UI", + "name": "customize-plugin-ui.md" + }, + { + "title": "定制元服务逻辑", + "name": "customize-meta-service-logic.md" + }, + { + "title": "开发设置器组件", + "name": "develop-configurator-components.md" + }, + { + "title": "AI插件使用前配置", + "name": "ai-plugin-configuration.md" + }, + { + "title": "如何自定义主题", + "name": "how-to-custom-theme.md" + } ] }, { "title": "API", "name": "api", "articles": [ - { "title": "API总览", "name": "api-overview.md" }, + { + "title": "API总览", + "name": "api-overview.md" + }, { "title": "前端API", "name": "frontend-api", "articles": [ - { "title": "主包API", "name": "main-package-api.md" }, - { "title": "画布API", "name": "canvas-api.md" }, - { "title": "全局布局API", "name": "global-layout-api.md" }, - { "title": "物料API", "name": "material-api.md" }, - { "title": "设置面板API", "name": "settings-panel-api.md" }, - { "title": "预览API", "name": "preview-api.md" }, - { "title": "元服务API", "name": "globalService-api.md" }, - { "title": "注册表API", "name": "registry-api.md" } + { + "title": "主包API", + "name": "main-package-api.md" + }, + { + "title": "画布API", + "name": "canvas-api.md" + }, + { + "title": "全局布局API", + "name": "global-layout-api.md" + }, + { + "title": "物料API", + "name": "material-api.md" + }, + { + "title": "设置面板API", + "name": "settings-panel-api.md" + }, + { + "title": "预览API", + "name": "preview-api.md" + }, + { + "title": "元服务API", + "name": "globalService-api.md" + }, + { + "title": "注册表API", + "name": "registry-api.md" + } ] }, { "title": "后端API", "name": "backend-api", "articles": [ - { "title": "AI功能接口", "name": "ai-function-api.md" }, - { "title": "应用管理", "name": "app-management.md" }, - { "title": "区块分类", "name": "block-categories.md" }, - { "title": "应用工具类管理", "name": "app-utility-management.md" }, - { "title": "区块管理", "name": "block-management-api.md" }, - { "title": "数据源管理", "name": "data-source-management.md" }, - { "title": "DSL代码生成", "name": "dsl-code-generation.md" }, - { "title": "物料中心", "name": "material-center.md" }, - { "title": "页面管理", "name": "page-management-api.md" }, - { "title": "APP服务", "name": "app-services.md" } + { + "title": "AI功能接口", + "name": "ai-function-api.md" + }, + { + "title": "应用管理", + "name": "app-management.md" + }, + { + "title": "区块分类", + "name": "block-categories.md" + }, + { + "title": "应用工具类管理", + "name": "app-utility-management.md" + }, + { + "title": "区块管理", + "name": "block-management-api.md" + }, + { + "title": "数据源管理", + "name": "data-source-management.md" + }, + { + "title": "物料中心", + "name": "material-center.md" + }, + { + "title": "页面管理", + "name": "page-management-api.md" + }, + { + "title": "APP服务", + "name": "app-services.md" + } ] } ] @@ -193,9 +422,18 @@ "title": "实战案例", "name": "practical-cases", "articles": [ - { "title": "PDM元数据审批电子流", "name": "pdm-metadata-approval-workflow.md" }, - { "title": "图元编排设计器", "name": "graphical-element-arrangement-designer.md" }, - { "title": "SMB轻量应用服务", "name": "smb-lightweight-application-service.md" } + { + "title": "PDM元数据审批电子流", + "name": "pdm-metadata-approval-workflow.md" + }, + { + "title": "图元编排设计器", + "name": "graphical-element-arrangement-designer.md" + }, + { + "title": "SMB轻量应用服务", + "name": "smb-lightweight-application-service.md" + } ] } ] @@ -208,10 +446,22 @@ "title": "生态中心", "name": "ecosystem-center", "articles": [ - { "title": "介绍", "name": "ecosystem-intro.md" }, - { "title": "如何导入组件库", "name": "how-to-import-library.md" }, - { "title": "如何发布区块", "name": "how-to-publish-block.md" }, - { "title": "发布其他生态", "name": "publish-other-ecosystems.md" } + { + "title": "介绍", + "name": "ecosystem-intro.md" + }, + { + "title": "如何导入组件库", + "name": "how-to-import-library.md" + }, + { + "title": "如何发布区块", + "name": "how-to-publish-block.md" + }, + { + "title": "发布其他生态", + "name": "publish-other-ecosystems.md" + } ] }, { @@ -222,33 +472,57 @@ "title": "创建应用(创建空白应用、从模板创建应用)", "name": "create-application-blank-or-template.md" }, - { "title": "开发应用", "name": "develop-application.md" } + { + "title": "开发应用", + "name": "develop-application.md" + } ] }, { "title": "关于物料", "name": "about-materials", "articles": [ - { "title": "介绍", "name": "materials-intro.md" }, - { "title": "创建物料资产包", "name": "create-material-asset-package.md" }, - { "title": "添加组件库和区块", "name": "add-library-and-blocks.md" }, - { "title": "构建物料资产包", "name": "build-material-asset-package.md" } + { + "title": "介绍", + "name": "materials-intro.md" + }, + { + "title": "创建物料资产包", + "name": "create-material-asset-package.md" + }, + { + "title": "添加组件库和区块", + "name": "add-library-and-blocks.md" + }, + { + "title": "构建物料资产包", + "name": "build-material-asset-package.md" + } ] }, { "title": "关于设计器", "name": "about-designer", "articles": [ - { "title": "介绍", "name": "designer-intro.md" }, - { "title": "创建设计器", "name": "create-designer.md" }, + { + "title": "介绍", + "name": "designer-intro.md" + }, + { + "title": "创建设计器", + "name": "create-designer.md" + }, { "title": "定制物料资产包、主题、DSL、工具栏和插件栏", "name": "customize-material-package-themes-dsl-toolbar-plugins.md" }, - { "title": "定制设计器", "name": "customize-designer.md" } + { + "title": "定制设计器", + "name": "customize-designer.md" + } ] } ] } ] -} +} \ No newline at end of file diff --git a/lint-staged.config.js b/lint-staged.config.js index f794152af8..21f321f7ac 100644 --- a/lint-staged.config.js +++ b/lint-staged.config.js @@ -1,4 +1,4 @@ module.exports = { - './packages/**/**.{js,mjs,jsx,ts,mts,tsx,vue}': 'eslint', + './packages/**/**.{js,mjs,jsx,ts,mts,tsx,vue}': 'eslint --no-warn-ignored', './packages/**/**.{js,mjs,jsx,ts,mts,tsx,vue,html,json,less}': 'prettier --write' } diff --git a/mockServer/package.json b/mockServer/package.json index 54e51c7c4f..cefcc7092c 100644 --- a/mockServer/package.json +++ b/mockServer/package.json @@ -1,6 +1,6 @@ { "name": "@opentiny/tiny-engine-mock", - "version": "2.10.0-rc.0", + "version": "2.10.0", "publishConfig": { "access": "public" }, diff --git a/mockServer/src/assets/json/model.json b/mockServer/src/assets/json/model.json index a0dab4b340..8fa7d42d56 100644 --- a/mockServer/src/assets/json/model.json +++ b/mockServer/src/assets/json/model.json @@ -529,4 +529,4 @@ "current": 1, "pages": 1 } -} +} \ No newline at end of file diff --git a/mockServer/src/database/model.db b/mockServer/src/database/model.db new file mode 100644 index 0000000000..f94205f057 --- /dev/null +++ b/mockServer/src/database/model.db @@ -0,0 +1,2 @@ +{"_id":1,"id":5,"createdBy":"1","lastUpdatedBy":"1","tenantId":null,"renterId":null,"siteId":null,"appId":null,"platformId":1,"nameCn":"员工","nameEn":"staff","version":"1.0.0","modelUrl":"https://agent-alpha.opentiny.design/platform-center/api/model-data","parameters":[{"prop":"id","isModel":false,"type":"Number","required":true,"description":"主键","_RID":"row_1"},{"prop":"name","isModel":false,"type":"String","required":true,"description":"姓名","_RID":"row_2"},{"prop":"status","isModel":false,"type":"Enum","options":"[{\"value\":\"1\",\"label\":\"已转正\"},{\"value\":\"0\",\"label\":\"未转正\"}]","required":true,"description":"状态","_RID":"row_3"},{"prop":"test","type":"String","required":false,"description":"","isModel":false,"_RID":"row_4"}],"method":[{"name":"新增方法","nameEn":"insertApi","requestParameters":[{"prop":"nameEn","type":"String"},{"prop":"params","type":"Object","children":[{"prop":"id","isModel":false,"type":"Number","required":true,"description":"主键"},{"prop":"name","isModel":false,"type":"String","required":true,"description":"姓名"},{"prop":"status","isModel":false,"type":"Enum","options":"[{\"value\":\"1\",\"label\":\"已转正\"},{\"value\":\"0\",\"label\":\"未转正\"}]","required":true,"description":"状态"},{"prop":"test","type":"String","required":false,"description":""}]}],"responseParameters":[{"prop":"code","type":"Number"},{"prop":"message","type":"String"},{"prop":"data","type":"Enum"}]},{"name":"修改方法","nameEn":"updateApi","requestParameters":[{"prop":"nameEn","type":"String"},{"prop":"data","type":"Object","children":[{"prop":"id","isModel":false,"type":"Number","required":true,"description":"主键"},{"prop":"name","isModel":false,"type":"String","required":true,"description":"姓名"},{"prop":"status","isModel":false,"type":"Enum","options":"[{\"value\":\"1\",\"label\":\"已转正\"},{\"value\":\"0\",\"label\":\"未转正\"}]","required":true,"description":"状态"},{"prop":"test","type":"String","required":false,"description":""}]},{"prop":"params","type":"Object","children":[{"prop":"id","isModel":false,"type":"Number","required":true,"description":"主键"},{"prop":"name","isModel":false,"type":"String","required":true,"description":"姓名"},{"prop":"status","isModel":false,"type":"Enum","options":"[{\"value\":\"1\",\"label\":\"已转正\"},{\"value\":\"0\",\"label\":\"未转正\"}]","required":true,"description":"状态"},{"prop":"test","type":"String","required":false,"description":""}]}],"responseParameters":[{"prop":"code","type":"Number"},{"prop":"message","type":"String"},{"prop":"data","type":"Enum"}]},{"name":"查询方法","nameEn":"queryApi","requestParameters":[{"prop":"nameEn","type":"String"},{"prop":"currentPage","type":"Number"},{"prop":"pageSize","type":"Number"},{"prop":"nameCn","type":"String"},{"prop":"params","type":"Object","children":[{"prop":"id","isModel":false,"type":"Number","required":true,"description":"主键"},{"prop":"name","isModel":false,"type":"String","required":true,"description":"姓名"},{"prop":"status","isModel":false,"type":"Enum","options":"[{\"value\":\"1\",\"label\":\"已转正\"},{\"value\":\"0\",\"label\":\"未转正\"}]","required":true,"description":"状态"},{"prop":"test","type":"String","required":false,"description":""}]}],"responseParameters":[{"prop":"total","type":"Number"},{"prop":"code","type":"Number"},{"prop":"message","type":"String"},{"prop":"data","type":"Enum"}]},{"name":"删除方法","nameEn":"deleteApi","requestParameters":[{"prop":"nameEn","type":"String"},{"prop":"id","type":"Number"}],"responseParameters":[{"prop":"code","type":"Number"},{"prop":"message","type":"String"},{"prop":"data","type":"Enum"}]}],"description":"1112","created_at":"2026-01-27 10:41:10","updated_at":"2026-01-27 10:41:10"} +{"_id":2,"id":6,"createdBy":"11","lastUpdatedBy":"11","tenantId":null,"renterId":null,"siteId":null,"appId":null,"platformId":1,"nameCn":"用户","nameEn":"user","version":"1.0.0","modelUrl":"https://agent-alpha.opentiny.design/platform-center/api","parameters":[{"prop":"name","type":"String","required":false,"description":""},{"prop":"age","type":"Number","required":false,"description":""}],"method":[{"name":"新增方法","nameEn":"insertApi","requestParameters":[{"prop":"nameEn","type":"String"},{"prop":"params","type":"Object","children":[{"prop":"name","type":"String","required":false,"description":""},{"prop":"age","type":"Number","required":false,"description":""}]}],"responseParameters":[{"prop":"code","type":"Number"},{"prop":"message","type":"String"},{"prop":"data","type":"Enum"}]},{"name":"修改方法","nameEn":"updateApi","requestParameters":[{"prop":"nameEn","type":"String"},{"prop":"data","type":"Object","children":[{"prop":"name","type":"String","required":false,"description":""},{"prop":"age","type":"Number","required":false,"description":""}]},{"prop":"params","type":"Object","children":[{"prop":"name","type":"String","required":false,"description":""},{"prop":"age","type":"Number","required":false,"description":""}]}],"responseParameters":[{"prop":"code","type":"Number"},{"prop":"message","type":"String"},{"prop":"data","type":"Enum"}]},{"name":"查询方法","nameEn":"queryApi","requestParameters":[{"prop":"nameEn","type":"String"},{"prop":"currentPage","type":"Number"},{"prop":"pageSize","type":"Number"},{"prop":"nameCn","type":"String"},{"prop":"params","type":"Object","children":[{"prop":"name","type":"String","required":false,"description":""},{"prop":"age","type":"Number","required":false,"description":""}]}],"responseParameters":[{"prop":"total","type":"Number"},{"prop":"code","type":"Number"},{"prop":"message","type":"String"},{"prop":"data","type":"Enum"}]},{"name":"删除方法","nameEn":"deleteApi","requestParameters":[{"prop":"nameEn","type":"String"},{"prop":"id","type":"Number"}],"responseParameters":[{"prop":"code","type":"Number"},{"prop":"message","type":"String"},{"prop":"data","type":"Enum"}]}],"description":"","created_at":"2026-01-29 03:00:21","updated_at":"2026-01-29 03:00:21"} diff --git a/mockServer/src/database/pages.db b/mockServer/src/database/pages.db index c90a9bb17a..808e35401d 100644 --- a/mockServer/src/database/pages.db +++ b/mockServer/src/database/pages.db @@ -1,4 +1,3 @@ {"name":"CreateVm","id":"1","app":"1","route":"CreateVm","page_content":{"state":{"dataDisk":[1,2,3]},"methods":{},"componentName":"Page","css":"body {\r\n background-color:#eef0f5 ;\r\n margin-bottom: 80px;\r\n}","props":{},"children":[{"componentName":"div","props":{"style":"padding-bottom: 10px; padding-top: 10px;"},"id":"2b2cabf0","children":[{"componentName":"TinyTimeLine","props":{"active":"2","data":[{"name":"基础配置"},{"name":"网络配置"},{"name":"高级配置"},{"name":"确认配置"}],"horizontal":true,"style":"border-radius: 0px;"},"id":"dd764b17"}]},{"componentName":"div","props":{"style":"border-width: 1px; border-style: solid; border-radius: 4px; border-color: #fff; padding-top: 10px; padding-bottom: 10px; padding-left: 10px; padding-right: 10px; box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px; background-color: #fff; margin-bottom: 10px;"},"id":"30c94cc8","children":[{"componentName":"TinyForm","props":{"labelWidth":"80px","labelPosition":"top","inline":false,"label-position":"left ","label-width":"150px","style":"border-radius: 0px;"},"children":[{"componentName":"TinyFormItem","props":{"label":"计费模式"},"children":[{"componentName":"TinyButtonGroup","props":{"data":[{"text":"包年/包月","value":"1"},{"text":"按需计费","value":"2"}],"modelValue":"1"},"id":"a8d84361"}],"id":"9f39f3e7"},{"componentName":"TinyFormItem","props":{"label":"区域"},"children":[{"componentName":"TinyButtonGroup","props":{"data":[{"text":"乌兰察布二零一","value":"1"}],"modelValue":"1","style":"border-radius: 0px; margin-right: 10px;"},"id":"c97ccd99"},{"componentName":"Text","props":{"text":"温馨提示:页面左上角切换区域","style":"background-color: [object Event]; color: #8a8e99; font-size: 12px;"},"id":"20923497"},{"componentName":"Text","props":{"text":"不同区域的云服务产品之间内网互不相通;请就近选择靠近您业务的区域,可减少网络时延,提高访问速度","style":"display: block; color: #8a8e99; border-radius: 0px; font-size: 12px;"},"id":"54780a26"}],"id":"4966384d"},{"componentName":"TinyFormItem","props":{"label":"可用区","style":"border-radius: 0px;"},"children":[{"componentName":"TinyButtonGroup","props":{"data":[{"text":"可用区1","value":"1"},{"text":"可用区2","value":"2"},{"text":"可用区3","value":"3"}],"modelValue":"1"},"id":"6184481b"}],"id":"690837bf"}],"id":"b6a425d4"}]},{"componentName":"div","props":{"style":"border-width: 1px; border-style: solid; border-radius: 4px; border-color: #fff; padding-top: 10px; padding-bottom: 10px; padding-left: 10px; padding-right: 10px; box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px; background-color: #fff; margin-bottom: 10px;"},"children":[{"componentName":"TinyForm","props":{"labelWidth":"80px","labelPosition":"top","inline":false,"label-position":"left ","label-width":"150px","style":"border-radius: 0px;"},"children":[{"componentName":"TinyFormItem","props":{"label":"CPU架构"},"children":[{"componentName":"TinyButtonGroup","props":{"data":[{"text":"x86计算","value":"1"},{"text":"鲲鹏计算","value":"2"}],"modelValue":"1"},"id":"7d33ced7"}],"id":"05ed5a79"},{"componentName":"TinyFormItem","props":{"label":"区域"},"children":[{"componentName":"div","props":{"style":"display: flex; justify-content: flex-start; align-items: center;"},"id":"606edf78","children":[{"componentName":"div","props":{"style":"display: flex; align-items: center; margin-right: 10px;"},"id":"f3f98246","children":[{"componentName":"Text","props":{"text":"vCPUs","style":"width: 80px;"},"id":"c287437e"},{"componentName":"TinySelect","props":{"modelValue":"","placeholder":"请选择","options":[{"value":"1","label":"黄金糕"},{"value":"2","label":"双皮奶"}]},"id":"4c43286b"}]},{"componentName":"div","props":{"style":"display: flex; align-items: center; margin-right: 10px;"},"children":[{"componentName":"Text","props":{"text":"内存","style":"width: 80px; border-radius: 0px;"},"id":"38b8fa1f"},{"componentName":"TinySelect","props":{"modelValue":"","placeholder":"请选择","options":[{"value":"1","label":"黄金糕"},{"value":"2","label":"双皮奶"}]},"id":"cd33328e"}],"id":"2b2c678f"},{"componentName":"div","props":{"style":"display: flex; align-items: center;"},"children":[{"componentName":"Text","props":{"text":"规格名称","style":"width: 80px;"},"id":"d3eb6352"},{"componentName":"TinySearch","props":{"modelValue":"","placeholder":"输入关键词"},"id":"21cb9282"}],"id":"b8e0f35c"}]},{"componentName":"div","props":{"style":"border-radius: 0px;"},"id":"5000c83e","children":[{"componentName":"TinyButtonGroup","props":{"data":[{"text":"通用计算型","value":"1"},{"text":"通用计算增强型","value":"2"},{"text":"内存优化型","value":"3"},{"text":"内存优化型","value":"4"},{"text":"磁盘增强型","value":"5"},{"text":"超高I/O型","value":"6"},{"text":"GPU加速型","value":"7"}],"modelValue":"1","style":"border-radius: 0px; margin-top: 12px;"},"id":"b8724703"},{"componentName":"TinyGrid","props":{"editConfig":{"trigger":"click","mode":"cell","showStatus":true},"columns":[{"type":"radio","width":60},{"field":"employees","title":"规格名称"},{"field":"created_date","title":"vCPUs | 内存(GiB)","sortable":true},{"field":"city","title":"CPU","sortable":true},{"title":"基准 / 最大带宽\t","sortable":true},{"title":"内网收发包","sortable":true}],"data":[{"id":"1","name":"GFD科技有限公司","city":"福州","employees":800,"created_date":"2014-04-30 00:56:00","boole":false},{"id":"2","name":"WWW科技有限公司","city":"深圳","employees":300,"created_date":"2016-07-08 12:36:22","boole":true}],"style":"margin-top: 12px; border-radius: 0px;","auto-resize":true},"id":"77701c25"},{"componentName":"div","props":{"style":"margin-top: 12px; border-radius: 0px;"},"id":"3339838b","children":[{"componentName":"Text","props":{"text":"当前规格","style":"width: 150px; display: inline-block;"},"id":"203b012b"},{"componentName":"Text","props":{"text":"通用计算型 | Si2.large.2 | 2vCPUs | 4 GiB","style":"font-weight: 700;"},"id":"87723f52"}]}]}],"id":"657fb2fc"}],"id":"d19b15cf"}],"id":"9991228b"},{"componentName":"div","props":{"style":"border-width: 1px; border-style: solid; border-radius: 4px; border-color: #fff; padding-top: 10px; padding-bottom: 10px; padding-left: 10px; padding-right: 10px; box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px; background-color: #fff; margin-bottom: 10px;"},"children":[{"componentName":"TinyForm","props":{"labelWidth":"80px","labelPosition":"top","inline":false,"label-position":"left ","label-width":"150px","style":"border-radius: 0px;"},"children":[{"componentName":"TinyFormItem","props":{"label":"镜像","style":"border-radius: 0px;"},"children":[{"componentName":"TinyButtonGroup","props":{"data":[{"text":"公共镜像","value":"1"},{"text":"私有镜像","value":"2"},{"text":"共享镜像","value":"3"}],"modelValue":"1"},"id":"922b14cb"},{"componentName":"div","props":{"style":"display: flex; margin-top: 12px; border-radius: 0px;"},"id":"6b679524","children":[{"componentName":"TinySelect","props":{"modelValue":"","placeholder":"请选择","options":[{"value":"1","label":"黄金糕"},{"value":"2","label":"双皮奶"}],"style":"width: 170px; margin-right: 10px;"},"id":"4851fff7"},{"componentName":"TinySelect","props":{"modelValue":"","placeholder":"请选择","options":[{"value":"1","label":"黄金糕"},{"value":"2","label":"双皮奶"}],"style":"width: 340px;"},"id":"a7183eb7"}]},{"componentName":"div","props":{"style":"margin-top: 12px;"},"id":"57aee314","children":[{"componentName":"Text","props":{"text":"请注意操作系统的语言类型。","style":"color: #e37d29;"},"id":"56d36c27"}]}],"id":"e3b02436"}],"id":"59aebf2b"}],"id":"87ff7b99"},{"componentName":"div","props":{"style":"border-width: 1px; border-style: solid; border-radius: 4px; border-color: #fff; padding-top: 10px; padding-bottom: 10px; padding-left: 10px; padding-right: 10px; box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px; background-color: #fff; margin-bottom: 10px;"},"children":[{"componentName":"TinyForm","props":{"labelWidth":"80px","labelPosition":"top","inline":false,"label-position":"left ","label-width":"150px","style":"border-radius: 0px;"},"children":[{"componentName":"TinyFormItem","props":{"label":"系统盘","style":"border-radius: 0px;"},"children":[{"componentName":"div","props":{"style":"display: flex;"},"id":"cddba5b8","children":[{"componentName":"TinySelect","props":{"modelValue":"","placeholder":"请选择","options":[{"value":"1","label":"黄金糕"},{"value":"2","label":"双皮奶"}],"style":"width: 200px; margin-right: 10px;"},"id":"a97fbe15"},{"componentName":"TinyInput","props":{"placeholder":"请输入","modelValue":"","style":"width: 120px; margin-right: 10px;"},"id":"1cde4c0f"},{"componentName":"Text","props":{"text":"GiB \nIOPS上限240,IOPS突发上限5,000","style":"color: #575d6c; font-size: 12px;"},"id":"2815d82d"}]}],"id":"50239a3a"}],"id":"e8582986"},{"componentName":"TinyForm","props":{"labelWidth":"80px","labelPosition":"top","inline":false,"label-position":"left ","label-width":"150px","style":"border-radius: 0px;"},"children":[{"componentName":"TinyFormItem","props":{"label":"数据盘","style":"border-radius: 0px;"},"children":[{"componentName":"div","props":{"style":"margin-top: 12px; display: flex;"},"id":"728c9825","children":[{"componentName":"Icon","props":{"style":"margin-right: 10px; width: 16px; height: 16px;","name":"IconPanelMini"},"id":"fded6930"},{"componentName":"TinySelect","props":{"modelValue":"","placeholder":"请选择","options":[{"value":"1","label":"黄金糕"},{"value":"2","label":"双皮奶"}],"style":"width: 200px; margin-right: 10px;"},"id":"62734e3f"},{"componentName":"TinyInput","props":{"placeholder":"请输入","modelValue":"","style":"width: 120px; margin-right: 10px;"},"id":"667c7926"},{"componentName":"Text","props":{"text":"GiB \nIOPS上限600,IOPS突发上限5,000","style":"color: #575d6c; font-size: 12px; margin-right: 10px;"},"id":"e7bc36d6"},{"componentName":"TinyInput","props":{"placeholder":"请输入","modelValue":"","style":"width: 120px;"},"id":"1bd56dc0"}],"loop":{"type":"JSExpression","value":"this.state.dataDisk"}},{"componentName":"div","props":{"style":"display: flex; margin-top: 12px; border-radius: 0px;"},"children":[{"componentName":"Icon","props":{"name":"IconPlus","style":"width: 16px; height: 16px; margin-right: 10px;"},"id":"65c89f2b"},{"componentName":"Text","props":{"text":"增加一块数据盘","style":"font-size: 12px; border-radius: 0px; margin-right: 10px;"},"id":"cb344071"},{"componentName":"Text","props":{"text":"您还可以挂载 21 块磁盘(云硬盘)","style":"color: #8a8e99; font-size: 12px;"},"id":"80eea996"}],"id":"e9e530ab"}],"id":"078e03ef"}],"id":"ccef886e"}],"id":"0fb7bd74"},{"componentName":"div","props":{"style":"border-width: 1px; border-style: solid; border-color: #ffffff; padding-top: 10px; padding-left: 10px; padding-right: 10px; box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px; background-color: #fff; position: fixed; inset: auto 0% 0% 0%; height: 80px; line-height: 80px; border-radius: 0px;"},"children":[{"componentName":"TinyForm","props":{"labelWidth":"80px","labelPosition":"top","inline":false,"label-position":"left ","label-width":"150px","style":"border-radius: 0px;"},"children":[],"id":"21ed4475"},{"componentName":"TinyRow","props":{"style":"border-radius: 0px; height: 100%;"},"children":[{"componentName":"TinyCol","props":{"span":"8"},"id":"b9d051a5","children":[{"componentName":"TinyRow","props":{"style":"border-radius: 0px;"},"children":[{"componentName":"TinyCol","props":{"span":"5","style":"display: flex;"},"id":"02352776","children":[{"componentName":"Text","props":{"text":"购买量","style":"margin-right: 10px;"},"id":"0cd9ed5c"},{"componentName":"TinyInput","props":{"placeholder":"请输入","modelValue":"","style":"width: 120px; margin-right: 10px;"},"id":"2f9cf442"},{"componentName":"Text","props":{"text":"台"},"id":"facd4481"}]},{"componentName":"TinyCol","props":{"span":"7"},"id":"82b6c659","children":[{"componentName":"div","props":{},"id":"9cd65874","children":[{"componentName":"Text","props":{"text":"配置费用","style":"font-size: 12px;"},"id":"b5a0a0da"},{"componentName":"Text","props":{"text":"¥1.5776","style":"padding-left: 10px; padding-right: 10px; color: #de504e;"},"id":"d9464214"},{"componentName":"Text","props":{"text":"/小时","style":"font-size: 12px;"},"id":"af7cc5e6"}]},{"componentName":"div","props":{},"id":"89063830","children":[{"componentName":"Text","props":{"text":"参考价格,具体扣费请以账单为准。","style":"font-size: 12px; border-radius: 0px;"},"id":"d8995fbc"},{"componentName":"Text","props":{"text":"了解计费详情","style":"font-size: 12px; color: #344899;"},"id":"b383c3e2"}]}]}],"id":"94fc0e43"}]},{"componentName":"TinyCol","props":{"span":"4","style":"display: flex; flex-direction: row-reverse; border-radius: 0px; height: 100%; justify-content: flex-start; align-items: center;"},"id":"10b73009","children":[{"componentName":"TinyButton","props":{"text":"下一步: 网络配置","type":"danger","style":"max-width: unset;"},"id":"0b584011"}]}],"id":"d414a473"}],"id":"e8ec029b"}],"fileName":"CreateVm"},"tenant":1,"isBody":false,"parentId":"0","group":"staticPages","depth":0,"isPage":true,"isDefault":false,"occupier":null,"isHome":false,"_id":"1"} {"name":"DemoPage","id":"5bhD7p5FUsUOTFRN","app":"1","route":"demopage","page_content":{"state":{},"methods":{},"componentName":"Page","css":"","props":{},"lifeCycles":{},"children":[{"componentName":"div","props":{},"id":"85375559","children":[{"componentName":"TinySwitch","props":{"modelValue":""},"id":"33433546"}]}],"dataSource":{"list":[]},"utils":[],"bridge":[],"inputs":[],"outputs":[],"fileName":"DemoPage"},"tenant":1,"isBody":false,"parentId":"0","group":"staticPages","depth":0,"isPage":true,"isDefault":false,"occupier":{"id":86,"username":"开发者","email":"developer@lowcode.com","confirmationToken":"dfb2c162-351f-4f44-ad5f-8998","is_admin":true},"isHome":false,"message":"Page auto save","_id":"5bhD7p5FUsUOTFRN"} -{"$$indexCreated":{"fieldName":"route","unique":true,"sparse":false}} -{"$$indexCreated":{"fieldName":"route","unique":true}} +{"$$indexCreated":{"fieldName":"_id","unique":true}} diff --git a/mockServer/src/mock/get/app-center/v1/apps/schema/1.json b/mockServer/src/mock/get/app-center/v1/apps/schema/1.json index 9240b466b8..8a00903ea7 100644 --- a/mockServer/src/mock/get/app-center/v1/apps/schema/1.json +++ b/mockServer/src/mock/get/app-center/v1/apps/schema/1.json @@ -1854,6 +1854,13 @@ "destructuring": true, "version": "0.1.16" }, + { + "componentName": "TinyActionMenu", + "package": "@opentiny/vue", + "exportName": "ActionMenu", + "destructuring": true, + "version": "0.1.16" + }, { "componentName": "TinyDialogBox", "package": "@opentiny/vue", @@ -2211,6 +2218,27 @@ "destructuring": true, "version": "3.22.0" }, + { + "componentName": "TinyHuichartsGraph", + "package": "@opentiny/vue-huicharts", + "exportName": "TinyHuichartsGraph", + "destructuring": true, + "version": "3.22.0" + }, + { + "componentName": "TinyHuichartsProcess", + "package": "@opentiny/vue-huicharts", + "exportName": "TinyHuichartsProcess", + "destructuring": true, + "version": "3.22.0" + }, + { + "componentName": "TinyHuichartsGauge", + "package": "@opentiny/vue-huicharts", + "exportName": "TinyHuichartsGauge", + "destructuring": true, + "version": "3.22.0" + }, { "componentName": "PortalHome", "main": "common/components/home", diff --git a/mockServer/src/mock/get/app-center/v1/apps/schema/16.json b/mockServer/src/mock/get/app-center/v1/apps/schema/16.json index 95402dd374..0e7d227952 100644 --- a/mockServer/src/mock/get/app-center/v1/apps/schema/16.json +++ b/mockServer/src/mock/get/app-center/v1/apps/schema/16.json @@ -1,1364 +1,1391 @@ { - "data": { - "meta": { - "name": "dashboard", - "tenant": 1, - "git_group": "", - "project_name": "", - "description": "数据看板", - "branch": "develop", - "is_demo": null, - "global_state": [], - "appId": "16", - "creator": "", - "gmt_create": "2022-06-08 03:19:01", - "gmt_modified": "2023-08-23 10:22:28" - }, - "dataSource": { - "list": [ - { - "id": 132, - "name": "getAllComponent", - "data": { - "data": [], - "type": "array" + "data": { + "meta": { + "name": "dashboard", + "tenant": 1, + "git_group": "", + "project_name": "", + "description": "数据看板", + "branch": "develop", + "is_demo": null, + "global_state": [], + "appId": "16", + "creator": "", + "gmt_create": "2022-06-08 03:19:01", + "gmt_modified": "2023-08-23 10:22:28" + }, + "dataSource": { + "list": [ + { + "id": 132, + "name": "getAllComponent", + "data": { + "data": [], + "type": "array" + }, + "tpl": null, + "app": "1", + "desc": null, + "created_at": "2022-06-28T06:26:26.000Z", + "updated_at": "2022-06-28T07:02:30.000Z" + }, + { + "id": 133, + "name": "getAllList", + "data": { + "columns": [ + { + "name": "test", + "title": "测试", + "field": "test", + "type": "string", + "format": {} + }, + { + "name": "test1", + "title": "测试1", + "field": "test1", + "type": "string", + "format": {} + } + ], + "type": "array", + "data": [ + { + "test": "test1", + "test1": "test1", + "_id": "341efc48" + }, + { + "test": "test2", + "test1": "test1", + "_id": "b86b516c" + }, + { + "test": "test3", + "test1": "test1", + "_id": "f680cd78" + } + ], + "options": { + "uri": "", + "method": "GET" + }, + "dataHandler": { + "type": "JSFunction", + "value": "function dataHandler(data) { \n return data \n}" }, - "tpl": null, - "app": "1", - "desc": null, - "created_at": "2022-06-28T06:26:26.000Z", - "updated_at": "2022-06-28T07:02:30.000Z" + "willFetch": { + "type": "JSFunction", + "value": "function willFetch(option) {\n return option \n}" + }, + "shouldFetch": { + "type": "JSFunction", + "value": "function shouldFetch(option) {\n return true \n}" + }, + "errorHandler": { + "type": "JSFunction", + "value": "function errorHandler(err) {}" + } }, - { - "id": 133, - "name": "getAllList", - "data": { - "columns": [ - { - "name": "test", - "title": "测试", - "field": "test", - "type": "string", - "format": {} - }, - { - "name": "test1", - "title": "测试1", - "field": "test1", - "type": "string", - "format": {} - } - ], - "type": "array", - "data": [ - { - "test": "test1", - "test1": "test1", - "_id": "341efc48" - }, - { - "test": "test2", - "test1": "test1", - "_id": "b86b516c" - }, - { - "test": "test3", - "test1": "test1", - "_id": "f680cd78" + "tpl": null, + "app": "1", + "desc": null, + "created_at": "2022-06-28T07:32:16.000Z", + "updated_at": "2023-01-19T03:29:11.000Z" + }, + { + "id": 135, + "name": "getAllMaterialList", + "data": { + "columns": [ + { + "name": "id", + "title": "id", + "field": "id", + "type": "string", + "format": {} + }, + { + "name": "name", + "title": "name", + "field": "name", + "type": "string", + "format": {} + }, + { + "name": "framework", + "title": "framework", + "field": "framework", + "type": "string", + "format": { + "required": true } - ], - "options": { - "uri": "", - "method": "GET" }, - "dataHandler": { - "type": "JSFunction", - "value": "function dataHandler(data) { \n return data \n}" + { + "name": "components", + "title": "components", + "field": "components", + "type": "string", + "format": {} + }, + { + "name": "content", + "title": "content", + "field": "content", + "type": "string", + "format": {} + }, + { + "name": "url", + "title": "url", + "field": "url", + "type": "string", + "format": {} }, - "willFetch": { - "type": "JSFunction", - "value": "function willFetch(option) {\n return option \n}" + { + "name": "published_at", + "title": "published_at", + "field": "published_at", + "type": "string", + "format": {} }, - "shouldFetch": { - "type": "JSFunction", - "value": "function shouldFetch(option) {\n return true \n}" + { + "name": "created_at", + "title": "created_at", + "field": "created_at", + "type": "string", + "format": {} }, - "errorHandler": { - "type": "JSFunction", - "value": "function errorHandler(err) {}" + { + "name": "updated_at", + "title": "updated_at", + "field": "updated_at", + "type": "string", + "format": {} + }, + { + "name": "published", + "title": "published", + "field": "published", + "type": "string", + "format": {} + }, + { + "name": "last_build_info", + "title": "last_build_info", + "field": "last_build_info", + "type": "string", + "format": {} + }, + { + "name": "tenant", + "title": "tenant", + "field": "tenant", + "type": "string", + "format": {} + }, + { + "name": "version", + "title": "version", + "field": "version", + "type": "string", + "format": {} + }, + { + "name": "description", + "title": "description", + "field": "description", + "type": "string", + "format": {} + } + ], + "type": "array", + "data": [ + { + "id": "f37123ec", + "url": "", + "name": "ng-material", + "tenant": "", + "content": "", + "version": "1.0.0", + "framework": "Angular", + "published": "", + "components": "", + "created_at": "2021-11-02T11:32:22.000Z", + "updated_at": "2021-11-02T11:32:22.000Z", + "description": "angular组件库物料", + "published_at": "2021-11-02T11:32:22.000Z", + "last_build_info": "", + "_id": "2a23e653" + }, + { + "id": "f37123ec", + "url": "", + "name": "ng-material", + "tenant": "", + "content": "", + "version": "1.0.0", + "framework": "Angular", + "published": "", + "components": "", + "created_at": "2021-11-02T11:32:22.000Z", + "updated_at": "2021-11-02T11:32:22.000Z", + "description": "angular组件库物料", + "published_at": "2021-11-02T11:32:22.000Z", + "last_build_info": "", + "_id": "06b253be" + }, + { + "id": "f37123ec", + "url": "", + "name": "ng-material", + "tenant": "", + "content": "", + "version": "1.0.0", + "framework": "Angular", + "published": "", + "components": "", + "created_at": "2021-11-02T11:32:22.000Z", + "updated_at": "2021-11-02T11:32:22.000Z", + "description": "angular组件库物料", + "published_at": "2021-11-02T11:32:22.000Z", + "last_build_info": "", + "_id": "c55a41ed" + }, + { + "id": "f37123ec", + "url": "", + "name": "ng-material", + "tenant": "", + "content": "", + "version": "1.0.0", + "framework": "Angular", + "published": "", + "components": "", + "created_at": "2021-11-02T11:32:22.000Z", + "updated_at": "2021-11-02T11:32:22.000Z", + "description": "angular组件库物料", + "published_at": "2021-11-02T11:32:22.000Z", + "last_build_info": "", + "_id": "f37123ec" + }, + { + "id": "7a63c1a2", + "url": "", + "name": "tiny-vue", + "tenant": "", + "content": "Tiny Vue物料", + "version": "1.0.0", + "framework": "Vue", + "published": "", + "components": "", + "created_at": "", + "updated_at": "", + "description": "Tiny Vue物料", + "published_at": "", + "last_build_info": "", + "_id": "7a63c1a2" } + ], + "options": { + "uri": "", + "method": "GET" + }, + "willFetch": { + "type": "JSFunction", + "value": "function willFetch(option) {\n return option \n}" }, - "tpl": null, - "app": "1", - "desc": null, - "created_at": "2022-06-28T07:32:16.000Z", - "updated_at": "2023-01-19T03:29:11.000Z" + "dataHandler": { + "type": "JSFunction", + "value": "function dataHandler(data) { \n return data \n}" + }, + "shouldFetch": { + "type": "JSFunction", + "value": "function shouldFetch(option) {\n return true \n}" + }, + "errorHandler": { + "type": "JSFunction", + "value": "function errorHandler(err) {}" + } }, - { - "id": 135, - "name": "getAllMaterialList", - "data": { - "columns": [ - { - "name": "id", - "title": "id", - "field": "id", - "type": "string", - "format": {} - }, - { - "name": "name", - "title": "name", - "field": "name", - "type": "string", - "format": {} - }, - { - "name": "framework", - "title": "framework", - "field": "framework", - "type": "string", - "format": { - "required": true - } - }, - { - "name": "components", - "title": "components", - "field": "components", - "type": "string", - "format": {} - }, - { - "name": "content", - "title": "content", - "field": "content", - "type": "string", - "format": {} - }, - { - "name": "url", - "title": "url", - "field": "url", - "type": "string", - "format": {} - }, - { - "name": "published_at", - "title": "published_at", - "field": "published_at", - "type": "string", - "format": {} - }, - { - "name": "created_at", - "title": "created_at", - "field": "created_at", - "type": "string", - "format": {} - }, - { - "name": "updated_at", - "title": "updated_at", - "field": "updated_at", - "type": "string", - "format": {} - }, - { - "name": "published", - "title": "published", - "field": "published", - "type": "string", - "format": {} - }, - { - "name": "last_build_info", - "title": "last_build_info", - "field": "last_build_info", - "type": "string", - "format": {} - }, - { - "name": "tenant", - "title": "tenant", - "field": "tenant", - "type": "string", - "format": {} - }, - { - "name": "version", - "title": "version", - "field": "version", - "type": "string", - "format": {} - }, - { - "name": "description", - "title": "description", - "field": "description", - "type": "string", - "format": {} - } - ], - "type": "array", - "data": [ - { - "id": "f37123ec", - "url": "", - "name": "ng-material", - "tenant": "", - "content": "", - "version": "1.0.0", - "framework": "Angular", - "published": "", - "components": "", - "created_at": "2021-11-02T11:32:22.000Z", - "updated_at": "2021-11-02T11:32:22.000Z", - "description": "angular组件库物料", - "published_at": "2021-11-02T11:32:22.000Z", - "last_build_info": "", - "_id": "2a23e653" - }, - { - "id": "f37123ec", - "url": "", - "name": "ng-material", - "tenant": "", - "content": "", - "version": "1.0.0", - "framework": "Angular", - "published": "", - "components": "", - "created_at": "2021-11-02T11:32:22.000Z", - "updated_at": "2021-11-02T11:32:22.000Z", - "description": "angular组件库物料", - "published_at": "2021-11-02T11:32:22.000Z", - "last_build_info": "", - "_id": "06b253be" - }, - { - "id": "f37123ec", - "url": "", - "name": "ng-material", - "tenant": "", - "content": "", - "version": "1.0.0", - "framework": "Angular", - "published": "", - "components": "", - "created_at": "2021-11-02T11:32:22.000Z", - "updated_at": "2021-11-02T11:32:22.000Z", - "description": "angular组件库物料", - "published_at": "2021-11-02T11:32:22.000Z", - "last_build_info": "", - "_id": "c55a41ed" - }, - { - "id": "f37123ec", - "url": "", - "name": "ng-material", - "tenant": "", - "content": "", - "version": "1.0.0", - "framework": "Angular", - "published": "", - "components": "", - "created_at": "2021-11-02T11:32:22.000Z", - "updated_at": "2021-11-02T11:32:22.000Z", - "description": "angular组件库物料", - "published_at": "2021-11-02T11:32:22.000Z", - "last_build_info": "", - "_id": "f37123ec" - }, - { - "id": "7a63c1a2", - "url": "", - "name": "tiny-vue", - "tenant": "", - "content": "Tiny Vue物料", - "version": "1.0.0", - "framework": "Vue", - "published": "", - "components": "", - "created_at": "", - "updated_at": "", - "description": "Tiny Vue物料", - "published_at": "", - "last_build_info": "", - "_id": "7a63c1a2" - } - ], - "options": { - "uri": "", - "method": "GET" + "tpl": null, + "app": "1", + "desc": null, + "created_at": "2022-06-29T00:57:50.000Z", + "updated_at": "2023-05-15T02:37:12.000Z" + }, + { + "id": 139, + "name": "treedata", + "data": { + "data": [ + { + "label": "level111", + "value": "111", + "id": "f6609643", + "pid": "", + "_RID": "row_4" + }, + { + "label": "level1-son", + "value": "111-1", + "id": "af1f937f", + "pid": "f6609643", + "_RID": "row_5" }, - "willFetch": { - "type": "JSFunction", - "value": "function willFetch(option) {\n return option \n}" + { + "label": "level222", + "value": "222", + "id": "28e3709c", + "pid": "", + "_RID": "row_6" }, - "dataHandler": { - "type": "JSFunction", - "value": "function dataHandler(data) { \n return data \n}" + { + "label": "level2-son", + "value": "222-1", + "id": "6b571bef", + "pid": "28e3709c", + "_RID": "row_5" }, - "shouldFetch": { - "type": "JSFunction", - "value": "function shouldFetch(option) {\n return true \n}" + { + "id": "6317c2cc", + "pid": "fdfa", + "label": "fsdfaa", + "value": "fsadf", + "_RID": "row_6" }, - "errorHandler": { - "type": "JSFunction", - "value": "function errorHandler(err) {}" + { + "id": "9cce369f", + "pid": "test", + "label": "test1", + "value": "001" } - }, - "tpl": null, - "app": "1", - "desc": null, - "created_at": "2022-06-29T00:57:50.000Z", - "updated_at": "2023-05-15T02:37:12.000Z" + ], + "type": "tree" }, - { - "id": 139, - "name": "treedata", - "data": { - "data": [ - { - "label": "level111", - "value": "111", - "id": "f6609643", - "pid": "", - "_RID": "row_4" - }, - { - "label": "level1-son", - "value": "111-1", - "id": "af1f937f", - "pid": "f6609643", - "_RID": "row_5" - }, - { - "label": "level222", - "value": "222", - "id": "28e3709c", - "pid": "", - "_RID": "row_6" - }, - { - "label": "level2-son", - "value": "222-1", - "id": "6b571bef", - "pid": "28e3709c", - "_RID": "row_5" - }, - { - "id": "6317c2cc", - "pid": "fdfa", - "label": "fsdfaa", - "value": "fsadf", - "_RID": "row_6" - }, - { - "id": "9cce369f", - "pid": "test", - "label": "test1", - "value": "001" + "tpl": null, + "app": "1", + "desc": null, + "created_at": "2022-06-30T06:13:57.000Z", + "updated_at": "2022-07-29T03:14:55.000Z" + }, + { + "id": 150, + "name": "componentList", + "data": { + "data": [ + { + "_RID": "row_1", + "name": "表单", + "isSelected": "true", + "description": "由按钮、输入框、选择器、单选框、多选框等控件组成,用以收集、校验、提交数据" + }, + { + "name": "按钮", + "isSelected": "false", + "description": "常用的操作按钮,提供包括默认按钮、图标按钮、图片按钮、下拉按钮等类型" + }, + { + "id": "490f8a00", + "_RID": "row_3", + "name": "表单项", + "framework": "", + "materials": "", + "description": "Form 组件下的 FormItem 配置" + }, + { + "id": "c259b8b3", + "_RID": "row_4", + "name": "开关", + "framework": "", + "materials": "", + "description": "关闭或打开" + }, + { + "id": "083ed9c7", + "_RID": "row_5", + "name": "互斥按钮组", + "framework": "", + "materials": "", + "description": "以按钮组的方式出现,常用于多项类似操作" + }, + { + "id": "09136cea", + "_RID": "row_6", + "name": "提示框", + "framework": "", + "materials": "", + "description": "Popover可通过对一个触发源操作触发弹出框,支持自定义弹出内容,延迟触发和渐变动画" + }, + { + "id": "a63b57d5", + "_RID": "row_7", + "name": "文字提示框", + "framework": "", + "materials": "", + "description": "动态显示提示信息,一般通过鼠标事件进行响应;提供 warning、error、info、success 四种类型显示不同类别的信" + }, + { + "id": "a0f6e8a3", + "_RID": "row_8", + "name": "树", + "framework": "", + "materials": "", + "description": "可进行展示有父子层级的数据,支持选择,异步加载等功能。但不推荐用它来展示菜单,展示菜单推荐使用树菜单" + }, + { + "id": "d1aa18fc", + "_RID": "row_9", + "name": "分页", + "framework": "", + "materials": "", + "description": "当数据量过多时,使用分页分解数据,常用于 Grid 和 Repeater 组件" + }, + { + "id": "ca49cc52", + "_RID": "row_10", + "name": "表格", + "framework": "", + "materials": "", + "description": "提供了非常强大数据表格功能,可以展示数据列表,可以对数据列表进行选择、编辑等" + }, + { + "id": "4e20ecc9", + "name": "搜索框", + "framework": "", + "materials": "", + "description": "指定条件对象进行搜索数据" + }, + { + "id": "6b093ee5", + "name": "折叠面板", + "framework": "", + "materials": "", + "description": "内容区可指定动态页面或自定义 html 等,支持展开收起操作" + }, + { + "id": "0a09abc0", + "name": "对话框", + "framework": "", + "materials": "", + "description": "模态对话框,在浮层中显示,引导用户进行相关操作" + }, + { + "id": "f814b901", + "name": "标签页签项", + "framework": "", + "materials": "", + "description": "tab页签" + }, + { + "id": "c5ae797c", + "name": "单选", + "framework": "", + "materials": "", + "description": "用于配置不同场景的选项,在一组备选项中进行单选" + }, + { + "id": "33d0c590", + "_RID": "row_13", + "name": "弹出编辑", + "framework": "", + "materials": "", + "description": "该组件只能在弹出的面板中选择数据,不能手动输入数据;弹出面板中显示为 Tree 组件或者 Grid 组件" + }, + { + "id": "16711dfa", + "_RID": "row_14", + "name": "下拉框", + "framework": "", + "materials": "", + "description": "Select 选择器是一种通过点击弹出下拉列表展示数据并进行选择的 UI 组件" + }, + { + "id": "a9fd190a", + "_RID": "row_15", + "name": "折叠面板项", + "framework": "", + "materials": "", + "description": "内容区可指定动态页面或自定义 html 等,支持展开收起操作" + }, + { + "id": "a7dfa9ec", + "_RID": "row_16", + "name": "复选框", + "framework": "", + "materials": "", + "description": "用于配置不同场景的选项,提供用户可在一组选项中进行多选" + }, + { + "id": "d4bb8330", + "name": "输入框", + "framework": "", + "materials": "", + "description": "通过鼠标或键盘输入字符" + }, + { + "id": "ced3dc83", + "name": "时间线", + "framework": "", + "materials": "", + "description": "时间线" + } + ], + "type": "array", + "columns": [ + { + "name": "name", + "type": "string", + "field": "name", + "title": "name", + "format": { + "max": 0, + "min": 0, + "dateTime": false, + "required": false, + "stringType": "" + } + }, + { + "name": "description", + "type": "string", + "field": "description", + "title": "description", + "format": { + "max": 0, + "min": 0, + "dateTime": false, + "required": false, + "stringType": "" + } + }, + { + "name": "isSelected", + "type": "string", + "field": "isSelected", + "title": "isSelected", + "format": { + "max": 0, + "min": 0, + "dateTime": false, + "required": false, + "stringType": "" } - ], - "type": "tree" + } + ], + "options": { + "uri": "http://localhost:9090/assets/json/bundle.json", + "method": "GET" + }, + "willFetch": { + "type": "JSFunction", + "value": "function willFetch(option) {\n return option \n}" + }, + "dataHandler": { + "type": "JSFunction", + "value": "function dataHandler(data) { \n return data \n}" + }, + "shouldFetch": { + "type": "JSFunction", + "value": "function shouldFetch(option) {\n return true \n}" }, - "tpl": null, - "app": "1", - "desc": null, - "created_at": "2022-06-30T06:13:57.000Z", - "updated_at": "2022-07-29T03:14:55.000Z" + "errorHandler": { + "type": "JSFunction", + "value": "function errorHandler(err) {}" + } }, - { - "id": 150, - "name": "componentList", - "data": { - "data": [ - { - "_RID": "row_1", - "name": "表单", - "isSelected": "true", - "description": "由按钮、输入框、选择器、单选框、多选框等控件组成,用以收集、校验、提交数据" - }, - { - "name": "按钮", - "isSelected": "false", - "description": "常用的操作按钮,提供包括默认按钮、图标按钮、图片按钮、下拉按钮等类型" - }, - { - "id": "490f8a00", - "_RID": "row_3", - "name": "表单项", - "framework": "", - "materials": "", - "description": "Form 组件下的 FormItem 配置" - }, - { - "id": "c259b8b3", - "_RID": "row_4", - "name": "开关", - "framework": "", - "materials": "", - "description": "关闭或打开" - }, - { - "id": "083ed9c7", - "_RID": "row_5", - "name": "互斥按钮组", - "framework": "", - "materials": "", - "description": "以按钮组的方式出现,常用于多项类似操作" - }, - { - "id": "09136cea", - "_RID": "row_6", - "name": "提示框", - "framework": "", - "materials": "", - "description": "Popover可通过对一个触发源操作触发弹出框,支持自定义弹出内容,延迟触发和渐变动画" - }, - { - "id": "a63b57d5", - "_RID": "row_7", - "name": "文字提示框", - "framework": "", - "materials": "", - "description": "动态显示提示信息,一般通过鼠标事件进行响应;提供 warning、error、info、success 四种类型显示不同类别的信" - }, - { - "id": "a0f6e8a3", - "_RID": "row_8", - "name": "树", - "framework": "", - "materials": "", - "description": "可进行展示有父子层级的数据,支持选择,异步加载等功能。但不推荐用它来展示菜单,展示菜单推荐使用树菜单" - }, - { - "id": "d1aa18fc", - "_RID": "row_9", - "name": "分页", - "framework": "", - "materials": "", - "description": "当数据量过多时,使用分页分解数据,常用于 Grid 和 Repeater 组件" - }, - { - "id": "ca49cc52", - "_RID": "row_10", - "name": "表格", - "framework": "", - "materials": "", - "description": "提供了非常强大数据表格功能,可以展示数据列表,可以对数据列表进行选择、编辑等" - }, - { - "id": "4e20ecc9", - "name": "搜索框", - "framework": "", - "materials": "", - "description": "指定条件对象进行搜索数据" - }, - { - "id": "6b093ee5", - "name": "折叠面板", - "framework": "", - "materials": "", - "description": "内容区可指定动态页面或自定义 html 等,支持展开收起操作" - }, - { - "id": "0a09abc0", - "name": "对话框", - "framework": "", - "materials": "", - "description": "模态对话框,在浮层中显示,引导用户进行相关操作" - }, - { - "id": "f814b901", - "name": "标签页签项", - "framework": "", - "materials": "", - "description": "tab页签" - }, - { - "id": "c5ae797c", - "name": "单选", - "framework": "", - "materials": "", - "description": "用于配置不同场景的选项,在一组备选项中进行单选" - }, - { - "id": "33d0c590", - "_RID": "row_13", - "name": "弹出编辑", - "framework": "", - "materials": "", - "description": "该组件只能在弹出的面板中选择数据,不能手动输入数据;弹出面板中显示为 Tree 组件或者 Grid 组件" - }, - { - "id": "16711dfa", - "_RID": "row_14", - "name": "下拉框", - "framework": "", - "materials": "", - "description": "Select 选择器是一种通过点击弹出下拉列表展示数据并进行选择的 UI 组件" - }, - { - "id": "a9fd190a", - "_RID": "row_15", - "name": "折叠面板项", - "framework": "", - "materials": "", - "description": "内容区可指定动态页面或自定义 html 等,支持展开收起操作" - }, - { - "id": "a7dfa9ec", - "_RID": "row_16", - "name": "复选框", - "framework": "", - "materials": "", - "description": "用于配置不同场景的选项,提供用户可在一组选项中进行多选" - }, - { - "id": "d4bb8330", - "name": "输入框", - "framework": "", - "materials": "", - "description": "通过鼠标或键盘输入字符" - }, - { - "id": "ced3dc83", - "name": "时间线", - "framework": "", - "materials": "", - "description": "时间线" + "tpl": null, + "app": "1", + "desc": null, + "created_at": "2022-07-04T02:20:07.000Z", + "updated_at": "2022-07-04T06:25:29.000Z" + }, + { + "id": 151, + "name": "selectedComponents", + "data": { + "columns": [ + { + "name": "name", + "title": "name", + "field": "name", + "type": "string", + "format": { + "required": false, + "stringType": "", + "min": 0, + "max": 0, + "dateTime": false } - ], - "type": "array", - "columns": [ - { - "name": "name", - "type": "string", - "field": "name", - "title": "name", - "format": { - "max": 0, - "min": 0, - "dateTime": false, - "required": false, - "stringType": "" - } - }, - { - "name": "description", - "type": "string", - "field": "description", - "title": "description", - "format": { - "max": 0, - "min": 0, - "dateTime": false, - "required": false, - "stringType": "" - } - }, - { - "name": "isSelected", - "type": "string", - "field": "isSelected", - "title": "isSelected", - "format": { - "max": 0, - "min": 0, - "dateTime": false, - "required": false, - "stringType": "" - } + }, + { + "name": "description", + "title": "description", + "field": "description", + "type": "string", + "format": { + "required": false, + "stringType": "", + "min": 0, + "max": 0, + "dateTime": false } - ], - "options": { - "uri": "http://localhost:9090/assets/json/bundle.json", - "method": "GET" }, - "willFetch": { - "type": "JSFunction", - "value": "function willFetch(option) {\n return option \n}" + { + "name": "isSelected", + "title": "isSelected", + "field": "isSelected", + "type": "string", + "format": { + "required": false, + "stringType": "", + "min": 0, + "max": 0, + "dateTime": false + } + } + ], + "type": "array", + "data": [ + { + "name": "标签页", + "description": "分隔内容上有关联但属于不同类别的数据集合", + "isSelected": "true", + "_RID": "row_2" }, - "dataHandler": { - "type": "JSFunction", - "value": "function dataHandler(data) { \n return data \n}" + { + "name": "布局列", + "description": "列配置信息", + "isSelected": "true", + "id": "76a7080a", + "_RID": "row_4" }, - "shouldFetch": { - "type": "JSFunction", - "value": "function shouldFetch(option) {\n return true \n}" + { + "name": "日期选择器", + "description": "用于设置/选择日期,包括年月/年月日/年月日时分/年月日时分秒日期格式", + "isSelected": "true", + "id": "76b20d73", + "_RID": "row_1" }, - "errorHandler": { - "type": "JSFunction", - "value": "function errorHandler(err) {}" + { + "name": "走马灯", + "description": "常用于一组图片或卡片轮播,当内容空间不足时,可以用走马灯的形式进行收纳,进行轮播展现", + "isSelected": "true", + "id": "4c884c3d" } - }, - "tpl": null, - "app": "1", - "desc": null, - "created_at": "2022-07-04T02:20:07.000Z", - "updated_at": "2022-07-04T06:25:29.000Z" + ] }, - { - "id": 151, - "name": "selectedComponents", - "data": { - "columns": [ - { - "name": "name", - "title": "name", - "field": "name", - "type": "string", - "format": { - "required": false, - "stringType": "", - "min": 0, - "max": 0, - "dateTime": false - } - }, - { - "name": "description", - "title": "description", - "field": "description", - "type": "string", - "format": { - "required": false, - "stringType": "", - "min": 0, - "max": 0, - "dateTime": false - } - }, - { - "name": "isSelected", - "title": "isSelected", - "field": "isSelected", - "type": "string", - "format": { - "required": false, - "stringType": "", - "min": 0, - "max": 0, - "dateTime": false - } - } - ], - "type": "array", - "data": [ - { - "name": "标签页", - "description": "分隔内容上有关联但属于不同类别的数据集合", - "isSelected": "true", - "_RID": "row_2" - }, - { - "name": "布局列", - "description": "列配置信息", - "isSelected": "true", - "id": "76a7080a", - "_RID": "row_4" - }, - { - "name": "日期选择器", - "description": "用于设置/选择日期,包括年月/年月日/年月日时分/年月日时分秒日期格式", - "isSelected": "true", - "id": "76b20d73", - "_RID": "row_1" - }, - { - "name": "走马灯", - "description": "常用于一组图片或卡片轮播,当内容空间不足时,可以用走马灯的形式进行收纳,进行轮播展现", - "isSelected": "true", - "id": "4c884c3d" - } - ] - }, - "tpl": null, - "app": "1", - "desc": null, - "created_at": "2022-07-04T03:04:05.000Z", - "updated_at": "2022-07-04T03:43:40.000Z" - } - ], - "dataHandler": { - "type": "JSFunction", - "value": "function dataHanlder(res){\n return res;\n}" + "tpl": null, + "app": "1", + "desc": null, + "created_at": "2022-07-04T03:04:05.000Z", + "updated_at": "2022-07-04T03:43:40.000Z" } + ], + "dataHandler": { + "type": "JSFunction", + "value": "function dataHanlder(res){\n return res;\n}" + } + }, + "i18n": { + "zh_CN": { + "lowcode.cca8d0ea": "应用", + "lowcode.c257d5e8": "查询", + "lowcode.61c8ac8c": "地方", + "lowcode.f53187a0": "测试", + "lowcode.97ad00dd": "创建物料资产包", + "lowcode.61dcef52": "terterere", + "lowcode.45f4c42a": "gdfgdf", + "lowcode.c6f5a652": "fsdaf", + "lowcode.34923432": "fdsafdsa", + "lowcode.48521e45": "fdsfds", + "lowcode.6534943e": "fdsafds", + "lowcode.44252642": "fdsafds", + "lowcode.2a743651": "sda", + "lowcode.24315357": "fdsafds", + "lowcode.44621691": "fdsafsd", + "lowcode.65636226": "fdsaf", + "lowcode.6426a4e2": "sd", + "lowcode.e41c6636": "aa", + "lowcode.51c23164": "aa", + "lowcode.17245b46": "aa", + "lowcode.4573143c": "aa", + "lowcode.56432442": "aa", + "lowcode.33566643": "aa", + "lowcode.565128f3": "aa", + "lowcode.56643835": "aa", + "lowcode.33311134": "aa", + "lowcode.44326643": "aa", + "lowcode.36223242": "aa" }, - "i18n": { - "zh_CN": { - "lowcode.cca8d0ea": "应用", - "lowcode.c257d5e8": "查询", - "lowcode.61c8ac8c": "地方", - "lowcode.f53187a0": "测试", - "lowcode.97ad00dd": "创建物料资产包", - "lowcode.61dcef52": "terterere", - "lowcode.45f4c42a": "gdfgdf", - "lowcode.c6f5a652": "fsdaf", - "lowcode.34923432": "fdsafdsa", - "lowcode.48521e45": "fdsfds", - "lowcode.6534943e": "fdsafds", - "lowcode.44252642": "fdsafds", - "lowcode.2a743651": "sda", - "lowcode.24315357": "fdsafds", - "lowcode.44621691": "fdsafsd", - "lowcode.65636226": "fdsaf", - "lowcode.6426a4e2": "sd", - "lowcode.e41c6636": "aa", - "lowcode.51c23164": "aa", - "lowcode.17245b46": "aa", - "lowcode.4573143c": "aa", - "lowcode.56432442": "aa", - "lowcode.33566643": "aa", - "lowcode.565128f3": "aa", - "lowcode.56643835": "aa", - "lowcode.33311134": "aa", - "lowcode.44326643": "aa", - "lowcode.36223242": "aa" - }, - "en_US": { - "lowcode.cca8d0ea": "app", - "lowcode.c257d5e8": "search", - "lowcode.61c8ac8c": "dsdsa", - "lowcode.f53187a0": "test", - "lowcode.97ad00dd": "createMaterial", - "lowcode.61dcef52": "sadasda", - "lowcode.45f4c42a": "gfdgfd", - "lowcode.c6f5a652": "fsdafds", - "lowcode.34923432": "fdsafds", - "lowcode.6534943e": "fdsafdsa", - "lowcode.44252642": "aaaa", - "lowcode.2a743651": "fdsaf", - "lowcode.24315357": "fsdafds", - "lowcode.44621691": "sd", - "lowcode.65636226": "fdsfsd", - "lowcode.6426a4e2": "fdsafsd", - "lowcode.e41c6636": "aa", - "lowcode.51c23164": "aa", - "lowcode.17245b46": "aa", - "lowcode.4573143c": "a", - "lowcode.56432442": "aa", - "lowcode.33566643": "aa", - "lowcode.565128f3": "aa", - "lowcode.56643835": "aa", - "lowcode.33311134": "aa", - "lowcode.44326643": "aa", - "lowcode.36223242": "aa" + "en_US": { + "lowcode.cca8d0ea": "app", + "lowcode.c257d5e8": "search", + "lowcode.61c8ac8c": "dsdsa", + "lowcode.f53187a0": "test", + "lowcode.97ad00dd": "createMaterial", + "lowcode.61dcef52": "sadasda", + "lowcode.45f4c42a": "gfdgfd", + "lowcode.c6f5a652": "fsdafds", + "lowcode.34923432": "fdsafds", + "lowcode.6534943e": "fdsafdsa", + "lowcode.44252642": "aaaa", + "lowcode.2a743651": "fdsaf", + "lowcode.24315357": "fsdafds", + "lowcode.44621691": "sd", + "lowcode.65636226": "fdsfsd", + "lowcode.6426a4e2": "fdsafsd", + "lowcode.e41c6636": "aa", + "lowcode.51c23164": "aa", + "lowcode.17245b46": "aa", + "lowcode.4573143c": "a", + "lowcode.56432442": "aa", + "lowcode.33566643": "aa", + "lowcode.565128f3": "aa", + "lowcode.56643835": "aa", + "lowcode.33311134": "aa", + "lowcode.44326643": "aa", + "lowcode.36223242": "aa" + } + }, + "componentsTree": [], + "componentsMap": [ + { + "componentName": "TinyCarouselItem", + "package": "@opentiny/vue", + "exportName": "CarouselItem", + "destructuring": true, + "version": "0.1.16" + }, + { + "componentName": "TinyCheckboxButton", + "package": "@opentiny/vue", + "exportName": "CheckboxButton", + "destructuring": true, + "version": "0.1.17" + }, + { + "componentName": "TinyTree", + "package": "@opentiny/vue", + "exportName": "Tree", + "destructuring": true, + "version": "0.1.16" + }, + { + "componentName": "TinyPopover", + "package": "@opentiny/vue", + "exportName": "Popover", + "destructuring": true, + "version": "0.1.16" + }, + { + "componentName": "TinyTooltip", + "package": "@opentiny/vue", + "exportName": "Tooltip", + "destructuring": true, + "version": "3.2.0" + }, + { + "componentName": "TinyCol", + "package": "@opentiny/vue", + "exportName": "Col", + "destructuring": true, + "version": "0.1.16" + }, + { + "componentName": "TinyDropdownItem", + "package": "@opentiny/vue", + "exportName": "DropdownItem", + "destructuring": true, + "version": "0.1.16" + }, + { + "componentName": "TinyPager", + "package": "@opentiny/vue", + "exportName": "Pager", + "destructuring": true, + "version": "0.1.16" + }, + { + "componentName": "TinyPlusAccessdeclined", + "package": "@opentiny/vue", + "exportName": "AccessDeclined", + "destructuring": true, + "version": "3.4.1" + }, + { + "componentName": "TinyPlusFrozenPage", + "package": "@opentiny/vue", + "exportName": "FrozenPage", + "destructuring": true, + "version": "3.4.1" + }, + { + "componentName": "TinyPlusNonSupportRegion", + "package": "@opentiny/vue", + "exportName": "NonSupportRegion", + "destructuring": true, + "version": "3.4.1" + }, + { + "componentName": "TinyPlusBeta", + "package": "@opentiny/vue", + "exportName": "Beta", + "destructuring": true, + "version": "3.4.1" + }, + { + "componentName": "TinySearch", + "package": "@opentiny/vue", + "exportName": "Search", + "destructuring": true, + "version": "0.1.13" + }, + { + "componentName": "TinyRow", + "package": "@opentiny/vue", + "exportName": "Row", + "destructuring": true, + "version": "0.1.16" + }, + { + "componentName": "TinyFormItem", + "package": "@opentiny/vue", + "exportName": "FormItem", + "destructuring": true, + "version": "0.1.16" + }, + { + "componentName": "TinyAlert", + "package": "@opentiny/vue", + "exportName": "Alert", + "destructuring": true, + "version": "3.2.0" + }, + { + "componentName": "TinyInput", + "package": "@opentiny/vue", + "exportName": "Input", + "destructuring": true, + "version": "0.1.16" + }, + { + "componentName": "TinyTabs", + "package": "@opentiny/vue", + "exportName": "Tabs", + "destructuring": true, + "version": "0.1.16" + }, + { + "componentName": "TinyDropdownMenu", + "package": "@opentiny/vue", + "exportName": "DropdownMenu", + "destructuring": true, + "version": "0.1.16" + }, + { + "componentName": "TinyActionMenu", + "package": "@opentiny/vue", + "exportName": "ActionMenu", + "destructuring": true, + "version": "0.1.16" + }, + { + "componentName": "TinyDialogBox", + "package": "@opentiny/vue", + "exportName": "DialogBox", + "destructuring": true, + "version": "3.2.0" + }, + { + "componentName": "TinySwitch", + "package": "@opentiny/vue", + "exportName": "Switch", + "destructuring": true, + "version": "0.1.16" + }, + { + "componentName": "TinyTimeLine", + "package": "@opentiny/vue", + "exportName": "TimeLine", + "destructuring": true, + "version": "0.1.16" + }, + { + "componentName": "TinyTabItem", + "package": "@opentiny/vue", + "exportName": "TabItem", + "destructuring": true, + "version": "0.1.16" + }, + { + "componentName": "TinyRadio", + "package": "@opentiny/vue", + "exportName": "Radio", + "destructuring": true, + "version": "0.1.16" + }, + { + "componentName": "TinyForm", + "package": "@opentiny/vue", + "exportName": "Form", + "destructuring": true, + "version": "0.1.16" + }, + { + "componentName": "TinyGrid", + "package": "@opentiny/vue", + "exportName": "Grid", + "destructuring": true, + "version": "0.1.16" + }, + { + "componentName": "TinyGridColumn", + "package": "@opentiny/vue", + "exportName": "TinyGridColumn", + "destructuring": true, + "version": "0.1.16" + }, + { + "componentName": "TinyNumeric", + "package": "@opentiny/vue", + "exportName": "Numeric", + "destructuring": true, + "version": "0.1.16" + }, + { + "componentName": "TinyCheckboxGroup", + "package": "@opentiny/vue", + "exportName": "CheckboxGroup", + "destructuring": true, + "version": "0.1.17" + }, + { + "componentName": "TinyCheckbox", + "package": "@opentiny/vue", + "exportName": "Checkbox", + "destructuring": true, + "version": "3.20.0" + }, + { + "componentName": "TinySelect", + "package": "@opentiny/vue", + "exportName": "Select", + "destructuring": true, + "version": "0.1.16" + }, + { + "componentName": "TinyButton", + "package": "@opentiny/vue", + "exportName": "Button", + "destructuring": true, + "version": "0.1.16" + }, + { + "componentName": "TinyButtonGroup", + "package": "@opentiny/vue", + "exportName": "ButtonGroup", + "destructuring": true, + "version": "0.1.16" + }, + { + "componentName": "TinyCarousel", + "package": "@opentiny/vue", + "exportName": "Carousel", + "destructuring": true, + "version": "0.1.16" + }, + { + "componentName": "TinyPopeditor", + "package": "@opentiny/vue", + "exportName": "Popeditor", + "destructuring": true, + "version": "0.1.16" + }, + { + "componentName": "TinyDatePicker", + "package": "@opentiny/vue", + "exportName": "DatePicker", + "destructuring": true, + "version": "0.1.16" + }, + { + "componentName": "TinyDropdown", + "package": "@opentiny/vue", + "exportName": "Dropdown", + "destructuring": true, + "version": "0.1.20" + }, + { + "componentName": "TinyChartHistogram", + "package": "@opentiny/vue", + "exportName": "ChartHistogram", + "destructuring": true, + "version": "0.1.16" + }, + { + "componentName": "TinyCollapse", + "package": "@opentiny/vue", + "exportName": "Collapse", + "destructuring": true, + "version": "3.20.0" + }, + { + "componentName": "TinyCollapseItem", + "package": "@opentiny/vue", + "exportName": "CollapseItem", + "destructuring": true, + "version": "3.20.0" + }, + { + "componentName": "TinyBreadcrumb", + "package": "@opentiny/vue", + "exportName": "Breadcrumb", + "destructuring": true, + "version": "3.20.0" + }, + { + "componentName": "TinyBreadcrumbItem", + "package": "@opentiny/vue", + "exportName": "BreadcrumbItem", + "destructuring": true, + "version": "3.20.0" + }, + { + "componentName": "TinyRate", + "package": "@opentiny/vue", + "exportName": "TinyRate", + "destructuring": true, + "version": "3.22.0" + }, + { + "componentName": "TinySlider", + "package": "@opentiny/vue", + "exportName": "TinySlider", + "destructuring": true, + "version": "3.22.0" + }, + { + "componentName": "TinyCascader", + "package": "@opentiny/vue", + "exportName": "TinyCascader", + "destructuring": true, + "version": "3.22.0" + }, + { + "componentName": "TinySteps", + "package": "@opentiny/vue", + "exportName": "TinySteps", + "destructuring": true, + "version": "3.22.0" + }, + { + "componentName": "TinyTreeMenu", + "package": "@opentiny/vue", + "exportName": "TinyTreeMenu", + "destructuring": true, + "version": "3.22.0" + }, + { + "componentName": "TinyRadioGroup", + "package": "@opentiny/vue", + "exportName": "TinyRadioGroup", + "destructuring": true, + "version": "3.22.0" + }, + { + "componentName": "ElInput", + "package": "element-plus", + "exportName": "ElInput", + "destructuring": true, + "version": "2.4.2" + }, + { + "componentName": "ElButton", + "package": "element-plus", + "exportName": "ElButton", + "destructuring": true, + "version": "2.4.2" + }, + { + "componentName": "ElForm", + "package": "element-plus", + "exportName": "ElForm", + "destructuring": true, + "version": "2.4.2" + }, + { + "componentName": "ElFormItem", + "package": "element-plus", + "exportName": "ElFormItem", + "destructuring": true, + "version": "2.4.2" + }, + { + "componentName": "ElTable", + "package": "element-plus", + "exportName": "ElTable", + "destructuring": true, + "version": "2.4.2" + }, + { + "componentName": "ElTableColumn", + "package": "element-plus", + "exportName": "ElTableColumn", + "destructuring": true, + "version": "2.4.2" + }, + { + "componentName": "TinyProgress", + "package": "@opentiny/vue", + "exportName": "TinyProgress", + "destructuring": true, + "version": "3.22.0" + }, + { + "componentName": "TinySkeleton", + "package": "@opentiny/vue", + "exportName": "TinySkeleton", + "destructuring": true, + "version": "3.22.0" + }, + { + "componentName": "TinyCard", + "package": "@opentiny/vue", + "exportName": "TinyCard", + "destructuring": true, + "version": "3.22.0" + }, + { + "componentName": "TinyCalendar", + "package": "@opentiny/vue", + "exportName": "TinyCalendar", + "destructuring": true, + "version": "3.22.0" + }, + { + "componentName": "TinyBadge", + "package": "@opentiny/vue", + "exportName": "TinyBadge", + "destructuring": true, + "version": "3.22.0" + }, + { + "componentName": "TinyTag", + "package": "@opentiny/vue", + "exportName": "TinyTag", + "destructuring": true, + "version": "3.22.0" + }, + { + "componentName": "TinyStatistic", + "package": "@opentiny/vue", + "exportName": "TinyStatistic", + "destructuring": true, + "version": "3.22.0" + }, + { + "componentName": "TinyHuichartsFunnel", + "package": "@opentiny/vue-huicharts", + "exportName": "TinyHuichartsFunnel", + "destructuring": true, + "version": "3.22.0" + }, + { + "componentName": "TinyHuichartsScatter", + "package": "@opentiny/vue-huicharts", + "exportName": "TinyHuichartsScatter", + "destructuring": true, + "version": "3.22.0" + }, + { + "componentName": "TinyHuichartsWaterfall", + "package": "@opentiny/vue-huicharts", + "exportName": "TinyHuichartsWaterfall", + "destructuring": true, + "version": "3.22.0" + }, + { + "componentName": "TinyHuichartsLine", + "package": "@opentiny/vue-huicharts", + "exportName": "TinyHuichartsLine", + "destructuring": true, + "version": "3.22.0" + }, + { + "componentName": "TinyHuichartsHistogram", + "package": "@opentiny/vue-huicharts", + "exportName": "TinyHuichartsHistogram", + "destructuring": true, + "version": "3.22.0" + }, + { + "componentName": "TinyHuichartsPie", + "package": "@opentiny/vue-huicharts", + "exportName": "TinyHuichartsPie", + "destructuring": true, + "version": "3.22.0" + }, + { + "componentName": "TinyHuichartsBar", + "package": "@opentiny/vue-huicharts", + "exportName": "TinyHuichartsBar", + "destructuring": true, + "version": "3.22.0" + }, + { + "componentName": "TinyHuichartsRing", + "package": "@opentiny/vue-huicharts", + "exportName": "TinyHuichartsRing", + "destructuring": true, + "version": "3.22.0" + }, + { + "componentName": "TinyHuichartsRadar", + "package": "@opentiny/vue-huicharts", + "exportName": "TinyHuichartsRadar", + "destructuring": true, + "version": "3.22.0" + }, + { + "componentName": "TinyHuichartsGraph", + "package": "@opentiny/vue-huicharts", + "exportName": "TinyHuichartsGraph", + "destructuring": true, + "version": "3.22.0" + }, + { + "componentName": "TinyHuichartsProcess", + "package": "@opentiny/vue-huicharts", + "exportName": "TinyHuichartsProcess", + "destructuring": true, + "version": "3.22.0" + }, + { + "componentName": "TinyHuichartsGauge", + "package": "@opentiny/vue-huicharts", + "exportName": "TinyHuichartsGauge", + "destructuring": true, + "version": "3.22.0" + }, + { + "componentName": "PortalHome", + "main": "common/components/home", + "destructuring": false, + "version": "1.0.0" + }, + { + "componentName": "PreviewBlock1", + "main": "preview", + "destructuring": false, + "version": "1.0.0" + }, + { + "componentName": "PortalHeader", + "main": "common", + "destructuring": false, + "version": "1.0.0" + }, + { + "componentName": "PortalBlock", + "main": "portal", + "destructuring": false, + "version": "1.0.0" + }, + { + "componentName": "PortalPermissionBlock", + "main": "", + "destructuring": false, + "version": "1.0.0" + } + ], + "bridge": [], + "utils": [ + { + "name": "axios", + "type": "npm", + "content": { + "type": "JSFunction", + "value": "", + "package": "axios", + "destructuring": false, + "exportName": "axios", + "cdnLink": "https://registry.npmmirror.com/axios/1.7.9/files/dist/esm/axios.min.js" } }, - "componentsTree": [], - "componentsMap": [ - { - "componentName": "TinyCarouselItem", - "package": "@opentiny/vue", - "exportName": "CarouselItem", - "destructuring": true, - "version": "0.1.16" - }, - { - "componentName": "TinyCheckboxButton", - "package": "@opentiny/vue", - "exportName": "CheckboxButton", - "destructuring": true, - "version": "0.1.17" - }, - { - "componentName": "TinyTree", - "package": "@opentiny/vue", - "exportName": "Tree", - "destructuring": true, - "version": "0.1.16" - }, - { - "componentName": "TinyPopover", - "package": "@opentiny/vue", - "exportName": "Popover", - "destructuring": true, - "version": "0.1.16" - }, - { - "componentName": "TinyTooltip", - "package": "@opentiny/vue", - "exportName": "Tooltip", - "destructuring": true, - "version": "3.2.0" - }, - { - "componentName": "TinyCol", - "package": "@opentiny/vue", - "exportName": "Col", - "destructuring": true, - "version": "0.1.16" - }, - { - "componentName": "TinyDropdownItem", - "package": "@opentiny/vue", - "exportName": "DropdownItem", - "destructuring": true, - "version": "0.1.16" - }, - { - "componentName": "TinyPager", - "package": "@opentiny/vue", - "exportName": "Pager", - "destructuring": true, - "version": "0.1.16" - }, - { - "componentName": "TinyPlusAccessdeclined", - "package": "@opentiny/vue", - "exportName": "AccessDeclined", - "destructuring": true, - "version": "3.4.1" - }, - { - "componentName": "TinyPlusFrozenPage", - "package": "@opentiny/vue", - "exportName": "FrozenPage", - "destructuring": true, - "version": "3.4.1" - }, - { - "componentName": "TinyPlusNonSupportRegion", - "package": "@opentiny/vue", - "exportName": "NonSupportRegion", - "destructuring": true, - "version": "3.4.1" - }, - { - "componentName": "TinyPlusBeta", - "package": "@opentiny/vue", - "exportName": "Beta", - "destructuring": true, - "version": "3.4.1" - }, - { - "componentName": "TinySearch", - "package": "@opentiny/vue", - "exportName": "Search", - "destructuring": true, - "version": "0.1.13" - }, - { - "componentName": "TinyRow", - "package": "@opentiny/vue", - "exportName": "Row", - "destructuring": true, - "version": "0.1.16" - }, - { - "componentName": "TinyFormItem", - "package": "@opentiny/vue", - "exportName": "FormItem", - "destructuring": true, - "version": "0.1.16" - }, - { - "componentName": "TinyAlert", - "package": "@opentiny/vue", - "exportName": "Alert", - "destructuring": true, - "version": "3.2.0" - }, - { - "componentName": "TinyInput", - "package": "@opentiny/vue", - "exportName": "Input", - "destructuring": true, - "version": "0.1.16" - }, - { - "componentName": "TinyTabs", - "package": "@opentiny/vue", - "exportName": "Tabs", - "destructuring": true, - "version": "0.1.16" - }, - { - "componentName": "TinyDropdownMenu", - "package": "@opentiny/vue", - "exportName": "DropdownMenu", - "destructuring": true, - "version": "0.1.16" - }, - { - "componentName": "TinyDialogBox", - "package": "@opentiny/vue", - "exportName": "DialogBox", - "destructuring": true, - "version": "3.2.0" - }, - { - "componentName": "TinySwitch", - "package": "@opentiny/vue", - "exportName": "Switch", - "destructuring": true, - "version": "0.1.16" - }, - { - "componentName": "TinyTimeLine", - "package": "@opentiny/vue", - "exportName": "TimeLine", - "destructuring": true, - "version": "0.1.16" - }, - { - "componentName": "TinyTabItem", - "package": "@opentiny/vue", - "exportName": "TabItem", - "destructuring": true, - "version": "0.1.16" - }, - { - "componentName": "TinyRadio", - "package": "@opentiny/vue", - "exportName": "Radio", - "destructuring": true, - "version": "0.1.16" - }, - { - "componentName": "TinyForm", - "package": "@opentiny/vue", - "exportName": "Form", - "destructuring": true, - "version": "0.1.16" - }, - { - "componentName": "TinyGrid", - "package": "@opentiny/vue", - "exportName": "Grid", - "destructuring": true, - "version": "0.1.16" - }, - { - "componentName": "TinyGridColumn", - "package": "@opentiny/vue", - "exportName": "TinyGridColumn", - "destructuring": true, - "version": "0.1.16" - }, - { - "componentName": "TinyNumeric", - "package": "@opentiny/vue", - "exportName": "Numeric", - "destructuring": true, - "version": "0.1.16" - }, - { - "componentName": "TinyCheckboxGroup", - "package": "@opentiny/vue", - "exportName": "CheckboxGroup", - "destructuring": true, - "version": "0.1.17" - }, - { - "componentName": "TinyCheckbox", - "package": "@opentiny/vue", - "exportName": "Checkbox", - "destructuring": true, - "version": "3.20.0" - }, - { - "componentName": "TinySelect", - "package": "@opentiny/vue", - "exportName": "Select", - "destructuring": true, - "version": "0.1.16" - }, - { - "componentName": "TinyButton", + { + "name": "Button", + "type": "npm", + "content": { "package": "@opentiny/vue", + "version": "", "exportName": "Button", + "subName": "", "destructuring": true, - "version": "0.1.16" - }, - { - "componentName": "TinyButtonGroup", - "package": "@opentiny/vue", - "exportName": "ButtonGroup", - "destructuring": true, - "version": "0.1.16" - }, - { - "componentName": "TinyCarousel", - "package": "@opentiny/vue", - "exportName": "Carousel", - "destructuring": true, - "version": "0.1.16" - }, - { - "componentName": "TinyPopeditor", - "package": "@opentiny/vue", - "exportName": "Popeditor", - "destructuring": true, - "version": "0.1.16" - }, - { - "componentName": "TinyDatePicker", - "package": "@opentiny/vue", - "exportName": "DatePicker", - "destructuring": true, - "version": "0.1.16" - }, - { - "componentName": "TinyDropdown", - "package": "@opentiny/vue", - "exportName": "Dropdown", - "destructuring": true, - "version": "0.1.20" - }, - { - "componentName": "TinyChartHistogram", - "package": "@opentiny/vue", - "exportName": "ChartHistogram", - "destructuring": true, - "version": "0.1.16" - }, - { - "componentName": "TinyCollapse", - "package": "@opentiny/vue", - "exportName": "Collapse", - "destructuring": true, - "version": "3.20.0" - }, - { - "componentName": "TinyCollapseItem", - "package": "@opentiny/vue", - "exportName": "CollapseItem", - "destructuring": true, - "version": "3.20.0" - }, - { - "componentName": "TinyBreadcrumb", - "package": "@opentiny/vue", - "exportName": "Breadcrumb", - "destructuring": true, - "version": "3.20.0" - }, - { - "componentName": "TinyBreadcrumbItem", - "package": "@opentiny/vue", - "exportName": "BreadcrumbItem", - "destructuring": true, - "version": "3.20.0" - }, - { - "componentName": "TinyRate", - "package": "@opentiny/vue", - "exportName": "TinyRate", - "destructuring": true, - "version": "3.22.0" - }, - { - "componentName": "TinySlider", - "package": "@opentiny/vue", - "exportName": "TinySlider", - "destructuring": true, - "version": "3.22.0" - }, - { - "componentName": "TinyCascader", - "package": "@opentiny/vue", - "exportName": "TinyCascader", - "destructuring": true, - "version": "3.22.0" - }, - { - "componentName": "TinySteps", - "package": "@opentiny/vue", - "exportName": "TinySteps", - "destructuring": true, - "version": "3.22.0" - }, - { - "componentName": "TinyTreeMenu", - "package": "@opentiny/vue", - "exportName": "TinyTreeMenu", - "destructuring": true, - "version": "3.22.0" - }, - { - "componentName": "TinyRadioGroup", - "package": "@opentiny/vue", - "exportName": "TinyRadioGroup", - "destructuring": true, - "version": "3.22.0" - }, - { - "componentName": "ElInput", - "package": "element-plus", - "exportName": "ElInput", - "destructuring": true, - "version": "2.4.2" - }, - { - "componentName": "ElButton", - "package": "element-plus", - "exportName": "ElButton", - "destructuring": true, - "version": "2.4.2" - }, - { - "componentName": "ElForm", - "package": "element-plus", - "exportName": "ElForm", - "destructuring": true, - "version": "2.4.2" - }, - { - "componentName": "ElFormItem", - "package": "element-plus", - "exportName": "ElFormItem", - "destructuring": true, - "version": "2.4.2" - }, - { - "componentName": "ElTable", - "package": "element-plus", - "exportName": "ElTable", - "destructuring": true, - "version": "2.4.2" - }, - { - "componentName": "ElTableColumn", - "package": "element-plus", - "exportName": "ElTableColumn", - "destructuring": true, - "version": "2.4.2" - }, - { - "componentName": "TinyProgress", - "package": "@opentiny/vue", - "exportName": "TinyProgress", - "destructuring": true, - "version": "3.22.0" - }, - { - "componentName": "TinySkeleton", - "package": "@opentiny/vue", - "exportName": "TinySkeleton", - "destructuring": true, - "version": "3.22.0" - }, - { - "componentName": "TinyCard", - "package": "@opentiny/vue", - "exportName": "TinyCard", - "destructuring": true, - "version": "3.22.0" - }, - { - "componentName": "TinyCalendar", - "package": "@opentiny/vue", - "exportName": "TinyCalendar", - "destructuring": true, - "version": "3.22.0" - }, - { - "componentName": "TinyBadge", + "main": "" + } + }, + { + "name": "Menu", + "type": "npm", + "content": { + "type": "JSFunction", + "value": "", "package": "@opentiny/vue", - "exportName": "TinyBadge", - "destructuring": true, - "version": "3.22.0" - }, - { - "componentName": "TinyTag", + "exportName": "NavMenu", + "destructuring": true + } + }, + { + "name": "Modal ", + "type": "npm", + "content": { "package": "@opentiny/vue", - "exportName": "TinyTag", + "version": "", + "exportName": "Modal ", + "subName": "", "destructuring": true, - "version": "3.22.0" - }, - { - "componentName": "TinyStatistic", + "main": "" + } + }, + { + "name": "Pager", + "type": "npm", + "content": { "package": "@opentiny/vue", - "exportName": "TinyStatistic", - "destructuring": true, - "version": "3.22.0" - }, - { - "componentName": "TinyHuichartsFunnel", - "package": "@opentiny/vue-huicharts", - "exportName": "TinyHuichartsFunnel", - "destructuring": true, - "version": "3.22.0" - }, - { - "componentName": "TinyHuichartsScatter", - "package": "@opentiny/vue-huicharts", - "exportName": "TinyHuichartsScatter", - "destructuring": true, - "version": "3.22.0" - }, - { - "componentName": "TinyHuichartsWaterfall", - "package": "@opentiny/vue-huicharts", - "exportName": "TinyHuichartsWaterfall", - "destructuring": true, - "version": "3.22.0" - }, - { - "componentName": "TinyHuichartsLine", - "package": "@opentiny/vue-huicharts", - "exportName": "TinyHuichartsLine", - "destructuring": true, - "version": "3.22.0" - }, - { - "componentName": "TinyHuichartsHistogram", - "package": "@opentiny/vue-huicharts", - "exportName": "TinyHuichartsHistogram", - "destructuring": true, - "version": "3.22.0" - }, - { - "componentName": "TinyHuichartsPie", - "package": "@opentiny/vue-huicharts", - "exportName": "TinyHuichartsPie", - "destructuring": true, - "version": "3.22.0" - }, - { - "componentName": "TinyHuichartsBar", - "package": "@opentiny/vue-huicharts", - "exportName": "TinyHuichartsBar", - "destructuring": true, - "version": "3.22.0" - }, - { - "componentName": "TinyHuichartsRing", - "package": "@opentiny/vue-huicharts", - "exportName": "TinyHuichartsRing", - "destructuring": true, - "version": "3.22.0" - }, - { - "componentName": "TinyHuichartsRadar", - "package": "@opentiny/vue-huicharts", - "exportName": "TinyHuichartsRadar", + "version": "", + "exportName": "Pager", + "subName": "", "destructuring": true, - "version": "3.22.0" - }, - { - "componentName": "PortalHome", - "main": "common/components/home", - "destructuring": false, - "version": "1.0.0" - }, - { - "componentName": "PreviewBlock1", - "main": "preview", - "destructuring": false, - "version": "1.0.0" - }, - { - "componentName": "PortalHeader", - "main": "common", - "destructuring": false, - "version": "1.0.0" - }, - { - "componentName": "PortalBlock", - "main": "portal", - "destructuring": false, - "version": "1.0.0" - }, - { - "componentName": "PortalPermissionBlock", - "main": "", - "destructuring": false, - "version": "1.0.0" + "main": "" } - ], - "bridge": [], - "utils": [ - { - "name": "axios", - "type": "npm", - "content": { - "type": "JSFunction", - "value": "", - "package": "axios", - "destructuring": false, - "exportName": "axios", - "cdnLink": "https://registry.npmmirror.com/axios/1.7.9/files/dist/esm/axios.min.js" - } - }, - { - "name": "Button", - "type": "npm", - "content": { - "package": "@opentiny/vue", - "version": "", - "exportName": "Button", - "subName": "", - "destructuring": true, - "main": "" - } - }, - { - "name": "Menu", - "type": "npm", - "content": { - "type": "JSFunction", - "value": "", - "package": "@opentiny/vue", - "exportName": "NavMenu", - "destructuring": true - } - }, - { - "name": "Modal ", - "type": "npm", - "content": { - "package": "@opentiny/vue", - "version": "", - "exportName": "Modal ", - "subName": "", - "destructuring": true, - "main": "" - } - }, - { - "name": "Pager", - "type": "npm", - "content": { - "package": "@opentiny/vue", - "version": "", - "exportName": "Pager", - "subName": "", - "destructuring": true, - "main": "" - } - }, - { - "name": "test", - "type": "function", - "content": { - "type": "JSFunction", - "value": "function test() {\r\n return 'test'\r\n}" - } - }, - { - "name": "util", - "type": "function", - "content": { - "type": "JSFunction", - "value": "function util () {\r\n console.log(321)\r\n}" - } + }, + { + "name": "test", + "type": "function", + "content": { + "type": "JSFunction", + "value": "function test() {\r\n return 'test'\r\n}" } - ], - "config": { - "sdkVersion": "1.0.3", - "historyMode": "hash", - "targetRootID": "app" - }, - "constants": "", - "css": "", - "version": "" + }, + { + "name": "util", + "type": "function", + "content": { + "type": "JSFunction", + "value": "function util () {\r\n console.log(321)\r\n}" + } + } + ], + "config": { + "sdkVersion": "1.0.3", + "historyMode": "hash", + "targetRootID": "app" }, - "locale": "zh-cn" - } - \ No newline at end of file + "constants": "", + "css": "", + "version": "" + }, + "locale": "zh-cn" +} diff --git a/mockServer/src/services/model.js b/mockServer/src/services/model.js index debb6493dd..e1d2e838f2 100644 --- a/mockServer/src/services/model.js +++ b/mockServer/src/services/model.js @@ -10,22 +10,51 @@ * */ -import { getResponseData } from '../tool/Common' -import modelList from '../assets/json/model.json' +import DateStore from '@seald-io/nedb' +import { getDatabasePath, getResponseData } from '../tool/Common' const defaultModel = { - createdBy: '86', - lastUpdatedBy: '86', + createdBy: '1', + lastUpdatedBy: '1', tenantId: null, renterId: null, siteId: null, appId: null, platformId: 1, - nameCn: 'test', - nameEn: 'test', + nameCn: '', + nameEn: '', version: '1.0.0', - modelUrl: '1', - parameters: [], + modelUrl: 'https://agent-alpha.opentiny.design/platform-center/api/model-data', + parameters: [ + { + prop: 'id', + isModel: false, + type: 'Number', + required: true, + description: '主键' + }, + { + prop: 'name', + isModel: false, + type: 'String', + required: true, + description: '姓名' + }, + { + prop: 'status', + isModel: false, + type: 'Enum', + options: '[{"value":"1","label":"已转正"},{"value":"0","label":"未转正"}]', + required: true, + description: '状态' + }, + { + prop: 'test', + type: 'String', + required: false, + description: '' + } + ], method: [ { name: '新增方法', @@ -33,13 +62,41 @@ const defaultModel = { requestParameters: [ { prop: 'nameEn', - type: 'String', - children: null + type: 'String' }, { prop: 'params', type: 'Object', - children: [] + children: [ + { + prop: 'id', + isModel: false, + type: 'Number', + required: true, + description: '主键' + }, + { + prop: 'name', + isModel: false, + type: 'String', + required: true, + description: '姓名' + }, + { + prop: 'status', + isModel: false, + type: 'Enum', + options: '[{"value":"1","label":"已转正"},{"value":"0","label":"未转正"}]', + required: true, + description: '状态' + }, + { + prop: 'test', + type: 'String', + required: false, + description: '' + } + ] } ], responseParameters: [ @@ -63,18 +120,75 @@ const defaultModel = { requestParameters: [ { prop: 'nameEn', - type: 'String', - children: null + type: 'String' }, { prop: 'data', type: 'Object', - children: [] + children: [ + { + prop: 'id', + isModel: false, + type: 'Number', + required: true, + description: '主键' + }, + { + prop: 'name', + isModel: false, + type: 'String', + required: true, + description: '姓名' + }, + { + prop: 'status', + isModel: false, + type: 'Enum', + options: '[{"value":"1","label":"已转正"},{"value":"0","label":"未转正"}]', + required: true, + description: '状态' + }, + { + prop: 'test', + type: 'String', + required: false, + description: '' + } + ] }, { prop: 'params', type: 'Object', - children: [] + children: [ + { + prop: 'id', + isModel: false, + type: 'Number', + required: true, + description: '主键' + }, + { + prop: 'name', + isModel: false, + type: 'String', + required: true, + description: '姓名' + }, + { + prop: 'status', + isModel: false, + type: 'Enum', + options: '[{"value":"1","label":"已转正"},{"value":"0","label":"未转正"}]', + required: true, + description: '状态' + }, + { + prop: 'test', + type: 'String', + required: false, + description: '' + } + ] } ], responseParameters: [ @@ -98,28 +212,53 @@ const defaultModel = { requestParameters: [ { prop: 'nameEn', - type: 'String', - children: null + type: 'String' }, { prop: 'currentPage', - type: 'Number', - children: null + type: 'Number' }, { prop: 'pageSize', - type: 'Number', - children: null + type: 'Number' }, { prop: 'nameCn', - type: 'String', - children: null + type: 'String' }, { prop: 'params', type: 'Object', - children: [] + children: [ + { + prop: 'id', + isModel: false, + type: 'Number', + required: true, + description: '主键' + }, + { + prop: 'name', + isModel: false, + type: 'String', + required: true, + description: '姓名' + }, + { + prop: 'status', + isModel: false, + type: 'Enum', + options: '[{"value":"1","label":"已转正"},{"value":"0","label":"未转正"}]', + required: true, + description: '状态' + }, + { + prop: 'test', + type: 'String', + required: false, + description: '' + } + ] } ], responseParameters: [ @@ -147,13 +286,11 @@ const defaultModel = { requestParameters: [ { prop: 'nameEn', - type: 'String', - children: null + type: 'String' }, { prop: 'id', - type: 'Number', - children: null + type: 'Number' } ], responseParameters: [ @@ -172,49 +309,56 @@ const defaultModel = { ] } ], - description: '', - created_at: '2026-01-30 04:34:25', - updated_at: '2026-01-30 04:34:25' + description: '' } -export default class AppsService { +export default class ModelService { constructor() { - this.modelList = modelList + this.db = new DateStore({ + filename: getDatabasePath('model.db'), + autoload: true + }) + + this.db.ensureIndex({ + fieldName: '_id', + unique: true + }) + this.modelList = [] } async create(params) { - let mockId = - this.modelList.data.records.length > 0 ? Math.max(...this.modelList.data.records.map((item) => item.id)) + 1 : 3 + let mockId = this.modelList.length > 0 ? Math.max(...this.modelList.map((item) => item.id)) + 1 : 3 const newModel = { ...defaultModel, id: mockId++, + created_at: new Date().toISOString(), + updated_at: new Date().toISOString(), ...params } - this.modelList.data.records.push(newModel) - return getResponseData(newModel) + + this.db.insert(newModel) + this.modelList.push(newModel) + + return getResponseData({ records: this.modelList }) } async delete(id) { - this.modelList.data.records = this.modelList.data.records.filter((item) => Number(item.id) !== Number(id)) + const result = await this.db.findOneAsync({ id: Number(id) }) + await this.db.removeAsync({ id: Number(id) }) - return getResponseData(this.modelList.data) + return getResponseData(result) } async list() { - return getResponseData(this.modelList.data) + this.modelList = await this.db.findAsync() + + return getResponseData({ records: this.modelList }) } async update(id, params) { - const index = this.modelList.data.records.findIndex((item) => Number(item.id) === Number(id)) - if (index === -1) { - return getResponseData({ success: false, message: '未找到应用' }) - } - - this.modelList.data.records[index] = { - ...this.modelList.data.records[index], - ...params - } + await this.db.updateAsync({ id: Number(id) }, { $set: params }) + const result = await this.db.findOneAsync({ id: Number(id) }) - return getResponseData(this.modelList.data.records[index]) + return getResponseData(result) } } diff --git a/mockServer/src/services/pages.js b/mockServer/src/services/pages.js index c4d40e68f3..c1a71dcaad 100644 --- a/mockServer/src/services/pages.js +++ b/mockServer/src/services/pages.js @@ -13,6 +13,17 @@ import DateStore from '@seald-io/nedb' import { getDatabasePath, getResponseData } from '../tool/Common' +const parsePageContent = (item) => { + if (item && item.page_content && typeof item.page_content === 'string') { + try { + item.page_content = JSON.parse(item.page_content) + } catch (e) { + // ignore + } + } + return item +} + export default class PageService { constructor() { this.db = new DateStore({ @@ -21,7 +32,7 @@ export default class PageService { }) this.db.ensureIndex({ - fieldName: 'route', + fieldName: '_id', unique: true }) @@ -68,32 +79,64 @@ export default class PageService { async create(params) { const model = params.isPage ? this.pageModel : this.folderModel const pageData = { ...model, ...params } + + if (!pageData.route) { + pageData.route = pageData.name || 'Untitled' + } + + const existing = await this.db.findOneAsync({ + app: pageData.app.toString(), + route: pageData.route + }) + + if (existing) { + return getResponseData(null, { + code: 'ROUTE_CONFLICT', + message: `Route "${pageData.route}" already exists in app "${pageData.app}"`, + status: 409 + }) + } + + if (pageData.page_content && typeof pageData.page_content === 'object') { + pageData.page_content = JSON.stringify(pageData.page_content) + } + const result = await this.db.insertAsync(pageData) const { _id } = result await this.db.updateAsync({ _id }, { $set: { id: _id } }) result.id = result._id - return getResponseData(result) + return getResponseData(parsePageContent(result)) } async update(id, params) { - await this.db.updateAsync({ _id: id }, { $set: params }) + const updateData = { ...params } + if (updateData.page_content && typeof updateData.page_content === 'object') { + updateData.page_content = JSON.stringify(updateData.page_content) + } + + await this.db.updateAsync({ _id: id }, { $set: updateData }) const result = await this.db.findOneAsync({ _id: id }) - return getResponseData(result) + return getResponseData(parsePageContent(result)) } async list(appId) { const result = await this.db.findAsync({ app: appId.toString() }) + if (Array.isArray(result)) { + result.forEach(parsePageContent) + } return getResponseData(result) } async detail(pageId) { const result = await this.db.findOneAsync({ _id: pageId }) - return getResponseData(result) + + return getResponseData(parsePageContent(result)) } async delete(pageId) { const result = await this.db.findOneAsync({ _id: pageId }) + await this.db.removeAsync({ _id: pageId }) - return getResponseData(result) + return getResponseData(parsePageContent(result)) } } diff --git a/packages/block-compiler/package.json b/packages/block-compiler/package.json index 79f11f0ba1..34a34d5608 100644 --- a/packages/block-compiler/package.json +++ b/packages/block-compiler/package.json @@ -1,6 +1,6 @@ { "name": "@opentiny/tiny-engine-block-compiler", - "version": "2.10.0-rc.0", + "version": "2.10.0", "publishConfig": { "access": "public" }, diff --git a/packages/build/vite-config/package.json b/packages/build/vite-config/package.json index cfae6a23da..8f86fa7dae 100644 --- a/packages/build/vite-config/package.json +++ b/packages/build/vite-config/package.json @@ -1,6 +1,6 @@ { "name": "@opentiny/tiny-engine-vite-config", - "version": "2.10.0-rc.0", + "version": "2.10.0", "description": "", "type": "module", "main": "./index.js", diff --git a/packages/build/vite-plugin-meta-comments/package.json b/packages/build/vite-plugin-meta-comments/package.json index 8eeedb386d..95c76b0a3a 100644 --- a/packages/build/vite-plugin-meta-comments/package.json +++ b/packages/build/vite-plugin-meta-comments/package.json @@ -1,6 +1,6 @@ { "name": "@opentiny/tiny-engine-vite-plugin-meta-comments", - "version": "2.10.0-rc.0", + "version": "2.10.0", "description": "", "type": "module", "main": "dist/index.cjs", diff --git a/packages/builtinComponent/package.json b/packages/builtinComponent/package.json index 698cb422d8..67631de957 100644 --- a/packages/builtinComponent/package.json +++ b/packages/builtinComponent/package.json @@ -1,6 +1,6 @@ { "name": "@opentiny/tiny-engine-builtin-component", - "version": "2.10.0-rc.0", + "version": "2.10.0", "description": "", "main": "dist/index.mjs", "module": "dist/index.mjs", diff --git a/packages/canvas/DesignCanvas/src/api/types.ts b/packages/canvas/DesignCanvas/src/api/types.ts index bb2a826645..4ba9f5be09 100644 --- a/packages/canvas/DesignCanvas/src/api/types.ts +++ b/packages/canvas/DesignCanvas/src/api/types.ts @@ -2,6 +2,28 @@ import type { Node, RootNode } from '../../../types' export type PageSchema = RootNode +export type AIHelperState = 'hidden' | 'chat' | 'loading' | 'confirm' | 'completed' + +export interface NodeAIStatus { + state: AIHelperState + collapsed?: boolean // 面板是否收起(收起时保留原状态,重新打开可恢复) + aiContext?: any + lastAIAction?: string + aiHistory?: Array<{ + timestamp: number + action: string + content: any + }> + chatContent?: string // 聊天内容 + // AI采纳状态相关字段 + originalNodeData?: any // AI修改前的节点数据备份 + aiModifiedNodeData?: any // AI修改后的节点数据 +} + +export interface NodeStatus { + [key: string]: any +} + export interface PageState { currentVm?: unknown currentSchema?: { [x: string]: any; id: string } @@ -17,7 +39,8 @@ export interface PageState { isSaved: boolean isLock: boolean isBlock: boolean - nodesStatus: Record + nodesStatus: Record + aiNodesStatus: Record // AI状态独立存储,避免与nodesStatus的可见性(false)冲突 loading: boolean } diff --git a/packages/canvas/DesignCanvas/src/api/useCanvas.ts b/packages/canvas/DesignCanvas/src/api/useCanvas.ts index 1c64aefc78..30d2c430af 100644 --- a/packages/canvas/DesignCanvas/src/api/useCanvas.ts +++ b/packages/canvas/DesignCanvas/src/api/useCanvas.ts @@ -21,6 +21,7 @@ import type { ChangePropsOperation, DeleteOperation, InsertOperation, + NodeAIStatus, NodeOperation, PageSchema, PageState, @@ -43,6 +44,7 @@ const defaultPageState: PageState = { isLock: false, isBlock: false, nodesStatus: {}, + aiNodesStatus: {}, loading: false } @@ -84,6 +86,39 @@ const rootSchema = ref([ } ]) +// 初始化单个节点的AI状态(使用独立的aiNodesStatus,避免与nodesStatus可见性冲突) +const initializeNodeAIStatus = (node: Node, initialStatus: Partial = {}) => { + pageState.aiNodesStatus[node.id] = { + state: 'hidden', + originalNodeData: deepClone(node), + aiModifiedNodeData: undefined, + aiContext: null, + lastAIAction: '', + aiHistory: [], + ...initialStatus + } +} + +// 初始化所有现有节点的AI状态 +const initializeAllNodesAIStatus = () => { + // 递归遍历 pageSchema 的 children 来初始化所有节点的AI状态 + const traverseNodes = (nodes: any[]) => { + if (!nodes) return + nodes.forEach((node) => { + if (node.id && !pageState.aiNodesStatus[node.id]) { + initializeNodeAIStatus(node) + } + if (Array.isArray(node.children) && node.children.length) { + traverseNodes(node.children) + } + }) + } + + if (pageState.pageSchema?.children) { + traverseNodes(pageState.pageSchema.children) + } +} + const handleTinyGridColumnsSlots = (node: Node) => { const columns = Array.isArray(node.props?.columns) ? node.props.columns : [] for (const columnItem of columns) { @@ -176,13 +211,26 @@ const jsonDiffPatchInstance = jsonDiffPatch.create({ const { publish } = useMessage() // 重置画布数据 -const resetCanvasState = async (state: Partial = {}) => { +// preserveAINodeStatus: 为true时保留aiNodesStatus并为新增节点补初始化(适用于AI/robot等schema热更新场景) +const resetCanvasState = async (state: Partial = {}, options?: { preserveAINodeStatus?: boolean }) => { const previousSchema = JSON.parse(JSON.stringify(pageState.pageSchema)) + const preserveAINodeStatus = options?.preserveAINodeStatus ?? false + + // 保留旧aiNodesStatus快照,用于后续diff补初始化 + const oldAINodesStatus: Record = preserveAINodeStatus ? { ...pageState.aiNodesStatus } : {} Object.assign(pageState, defaultPageState, state) nodesMap.value.clear() + if (preserveAINodeStatus) { + // 保留aiNodesStatus,后续只为新增节点补初始化 + pageState.aiNodesStatus = oldAINodesStatus + } else { + // 切换页面时清空所有节点的AI状态,避免旧页面的AI状态残留 + pageState.aiNodesStatus = {} + } + if (pageState.pageSchema) { if (!pageState.pageSchema.children) { pageState.pageSchema.children = [] @@ -200,14 +248,34 @@ const resetCanvasState = async (state: Partial = {}) => { nodesMap.value.set(0, { node: rootSchema.value, parent: pageState.pageSchema }) generateNodesMap(pageState.pageSchema.children, pageState.pageSchema) + + if (preserveAINodeStatus) { + // 为新增的节点初始化AI状态(已存在的不覆盖) + nodesMap.value.forEach(({ node }) => { + if (node.id && !pageState.aiNodesStatus[node.id]) { + initializeNodeAIStatus(node) + } + }) + } else { + // 初始化所有节点的AI状态 + initializeAllNodesAIStatus() + } } const diffPatch = jsonDiffPatchInstance.diff(previousSchema, pageState.pageSchema) - canvasApi.value?.clearSelect?.() + if (!preserveAINodeStatus) { + canvasApi.value?.clearSelect?.() + } + publish({ topic: 'schemaImport', data: { current: pageState.pageSchema, previous: previousSchema, diffPatch } }) } +// 更新页面schema,保留AI状态(委托resetCanvasState + preserveAINodeStatus) +const updatePageSchema = (newPageSchema: any) => { + resetCanvasState({ ...pageState, pageSchema: newPageSchema }, { preserveAINodeStatus: true }) +} + // 页面重置画布数据 const resetPageCanvasState = (state: Partial = {}) => { state.isBlock = false @@ -383,10 +451,28 @@ const operationTypeMap = { setNode(newNodeData, parentNode) + // 初始化新节点的AI状态 + if (newNodeData.id) { + initializeNodeAIStatus(newNodeData) + } + // 6. 如果新节点有子节点,递归构建 nodeMap if (Array.isArray(newNodeData?.children) && newNodeData.children.length > 0) { const newNode = getNode(newNodeData.id) generateNodesMap(newNodeData.children, newNode) + + // 递归初始化所有子节点的AI状态 + const initChildrenAIStatus = (children: Node[]) => { + children.forEach((child) => { + if (child.id) { + initializeNodeAIStatus(child) + } + if (Array.isArray(child?.children) && child.children.length > 0) { + initChildrenAIStatus(child.children) + } + }) + } + initChildrenAIStatus(newNodeData.children) } // 7. 返回插入结果 @@ -410,16 +496,18 @@ const operationTypeMap = { if (index > -1) { parent.children.splice(index, 1) nodesMap.value.delete(node.id) + delete pageState.aiNodesStatus[node.id] } let children = [...(node.children || [])] - // 递归清理 nodesMap + // 递归清理 nodesMap 和 aiNodesStatus while (children?.length) { const len = children.length children.forEach((item) => { const nodeItem = getNode(item.id) nodesMap.value.delete(item.id) + delete pageState.aiNodesStatus[item.id] if (Array.isArray(nodeItem?.children) && nodeItem?.children.length) { children.push(...nodeItem.children) @@ -597,7 +685,7 @@ const patchLatestSchema = (schema: unknown) => { } } -const importSchema = (data: any) => { +const importSchema = (data: any, options?: { preserveAINodeStatus?: boolean }) => { let importData = data if (typeof data === 'string') { @@ -609,11 +697,7 @@ const importSchema = (data: any) => { } } - // JSON 格式校验 - resetCanvasState({ - ...pageState, - pageSchema: importData - }) + resetCanvasState({ ...pageState, pageSchema: importData }, options) } const exportSchema = () => { @@ -650,6 +734,49 @@ const updateSchema = (data: Partial) => { publish({ topic: 'schemaChange', data: {} }) } +/** + * 恢复节点子树数据并重建nodesMap + * 用于AI回滚场景:恢复originalNodeData后需要同步清理/重建nodesMap + * @param nodeId 要恢复的节点ID + * @param restoredData 恢复后的节点数据(deepClone后的originalNodeData) + */ +const restoreNodeSubtree = (nodeId: string, restoredData: any) => { + // 1. 收集恢复前该节点子树中的所有ID(这些是需要从nodesMap中清理的) + const collectSubtreeIds = (node: any): string[] => { + const ids: string[] = [] + if (node?.id) ids.push(node.id) + if (Array.isArray(node?.children)) { + node.children.forEach((child: any) => ids.push(...collectSubtreeIds(child))) + } + return ids + } + + const currentNode = getNode(nodeId) + const oldIds = currentNode ? collectSubtreeIds(currentNode) : [] + // 获取当前节点的parent信息(在清理前保存) + const parentEntry = nodesMap.value.get(nodeId) + const parentNode = parentEntry?.parent + + // 2. 清理旧子树的nodesMap + oldIds.forEach((id) => nodesMap.value.delete(id)) + + // 3. 用恢复后的数据覆盖当前节点 + if (currentNode) { + Object.keys(currentNode).forEach((key) => delete currentNode[key]) + Object.assign(currentNode, restoredData) + } + + // 4. 重建该节点自身的nodesMap条目 + if (currentNode && parentNode) { + nodesMap.value.set(nodeId, { node: currentNode, parent: parentNode }) + } + + // 5. 重建子节点的nodesMap + if (Array.isArray(restoredData?.children) && restoredData.children.length && currentNode) { + generateNodesMap(restoredData.children, currentNode) + } +} + export default function () { return { pageState, @@ -684,6 +811,8 @@ export default function () { exportSchema, getSchema, getNodePath, - updateSchema + updateSchema, + updatePageSchema, + restoreNodeSubtree } } diff --git a/packages/canvas/container/assets/loading.webp b/packages/canvas/container/assets/loading.webp new file mode 100644 index 0000000000..ed71b43597 Binary files /dev/null and b/packages/canvas/container/assets/loading.webp differ diff --git a/packages/canvas/container/src/components/AIConfirmDialog.vue b/packages/canvas/container/src/components/AIConfirmDialog.vue new file mode 100644 index 0000000000..f3af12e385 --- /dev/null +++ b/packages/canvas/container/src/components/AIConfirmDialog.vue @@ -0,0 +1,115 @@ + + + + + diff --git a/packages/canvas/container/src/components/AILoadingDialog.vue b/packages/canvas/container/src/components/AILoadingDialog.vue new file mode 100644 index 0000000000..192d005451 --- /dev/null +++ b/packages/canvas/container/src/components/AILoadingDialog.vue @@ -0,0 +1,93 @@ + + + + diff --git a/packages/canvas/container/src/components/CanvasAIChat.vue b/packages/canvas/container/src/components/CanvasAIChat.vue new file mode 100644 index 0000000000..75bce3508c --- /dev/null +++ b/packages/canvas/container/src/components/CanvasAIChat.vue @@ -0,0 +1,71 @@ + + + + + diff --git a/packages/canvas/container/src/components/CanvasAction.vue b/packages/canvas/container/src/components/CanvasAction.vue index 9df3bc0cac..f3cd4a50ea 100644 --- a/packages/canvas/container/src/components/CanvasAction.vue +++ b/packages/canvas/container/src/components/CanvasAction.vue @@ -91,6 +91,39 @@
+ +
+ + + + + + +
@@ -136,6 +169,14 @@ import { import { useLayout, useMaterial, useCanvas, useMessage } from '@opentiny/tiny-engine-meta-register' import { Popover } from '@opentiny/vue' import shortCutPopover from './shortCutPopover.vue' +import CanvasAIChat from './CanvasAIChat.vue' +import AIConfirmDialog from './AIConfirmDialog.vue' +import AILoadingDialog from './AILoadingDialog.vue' +import { chat } from '../services/agentServices' +import { utils } from '@opentiny/tiny-engine-utils' +import useAIChat from '../composables/useAIChat' + +const { deepClone } = utils // 工具操作条高度 const OPTION_BAR_HEIGHT = 24 @@ -155,6 +196,9 @@ const STYLE_UNSET = 'unset' export default { components: { + AILoadingDialog, + CanvasAIChat, + AIConfirmDialog, IconDel: IconDel(), IconSetting: IconSetting(), IconChevronLeft: IconChevronLeft(), @@ -198,6 +242,29 @@ export default { }, emits: ['remove', 'selectSlot', 'setting'], setup(props) { + const { pageState: _pageState, getNode } = useCanvas() + + const { + getNodeAIStatus, + openNodeAIChat, + closeNodeAIHelper, + startNodeAILoading, + cancelNodeAILoading, + shouldShowNodeAIChat, + shouldShowNodeAILoading, + shouldShowNodeAIConfirm, + confirmNodeAIAction, + updateNodeAIStatus, + cancelNodeAIAction, + applyAIPatches, + buildAIChatRequest + } = useAIChat() + + // AI请求的AbortController,用于取消正在进行的请求 + let aiChatAbortController = null + // 递增token,用于防止并发请求的响应竞争 + let aiChatRequestToken = 0 + const remove = () => { removeNodeById(getCurrent().schema?.id) } @@ -283,6 +350,89 @@ export default { return config?.configure?.isModal }) + // 是否显示AI聊天界面 + const shouldShowAIChat = computed(() => { + const currentSchema = getCurrent().schema + if (!currentSchema?.id) { + return false + } + + return shouldShowNodeAIChat(currentSchema.id) + }) + + // 是否显示确认弹窗 + const shouldShowAIConfirm = computed(() => { + const currentSchema = getCurrent().schema + if (!currentSchema?.id) { + return false + } + + return shouldShowNodeAIConfirm(currentSchema.id) + }) + + // 是否显示AI加载状态 + const shouldShowAILoading = computed(() => { + const currentSchema = getCurrent().schema + if (!currentSchema?.id) { + return false + } + + return shouldShowNodeAILoading(currentSchema.id) + }) + + const showAIPopover = ref(false) + watch( + () => { + const currentSchema = getCurrent().schema + if (!currentSchema?.id) { + return false + } + const status = getNodeAIStatus(currentSchema?.id) + return status?.state !== 'hidden' && !status?.collapsed + }, + (val) => { + showAIPopover.value = val + } + ) + + // 切换AI助手显示/隐藏 + const openAIHelper = () => { + const currentSchema = getCurrent().schema + + if (!currentSchema?.id) { + return + } + + const currentStatus = getNodeAIStatus(currentSchema.id) + + if (currentStatus && currentStatus.collapsed) { + // 面板已收起,重新展开恢复原状态 + updateNodeAIStatus(currentSchema.id, { collapsed: false }) + } else if (currentStatus && currentStatus.state !== 'hidden') { + // 面板当前可见,收起面板但保留业务状态 + updateNodeAIStatus(currentSchema.id, { collapsed: true }) + } else { + // hidden状态,进入chat + openNodeAIChat(currentSchema.id) + } + } + + // 关闭AI助手(由其他组件调用,如AI聊天界面的关闭按钮) + const closeAIHelper = () => { + const currentSchema = getCurrent().schema + if (!currentSchema?.id) { + return + } + + const currentStatus = getNodeAIStatus(currentSchema.id) + // loading/confirm状态下只收起面板,保留状态以便重新打开恢复 + if (currentStatus && (currentStatus.state === 'loading' || currentStatus.state === 'confirm')) { + updateNodeAIStatus(currentSchema.id, { collapsed: true }) + } else { + closeNodeAIHelper(currentSchema.id) + } + } + const optionRef = ref(null) const fixStyle = ref('') @@ -633,6 +783,166 @@ export default { fixStyle.value = optionStyleValue }) + // AI聊天完成处理 + const handleAIChatComplete = async (content) => { + const currentSchema = getCurrent().schema + if (!currentSchema?.id) { + return + } + + // 先进入加载状态 + startNodeAILoading(currentSchema.id, 'AI正在处理您的请求...') + + // 在AI修改节点前,先刷新originalNodeData为当前最新节点数据 + // 避免取消/重新生成时回滚到过期的快照,丢失用户之前的普通编辑 + const currentNode = getNode(currentSchema.id) + if (currentNode) { + const currentStatus = getNodeAIStatus(currentSchema.id) + if (currentStatus) { + currentStatus.originalNodeData = deepClone(currentNode) + } + } + + // 创建新的AbortController用于取消请求,递增token防止响应竞争 + aiChatAbortController = new AbortController() + const currentToken = ++aiChatRequestToken + + try { + const params = await buildAIChatRequest(content) + const response = await chat(params, aiChatAbortController.signal) + + // 响应到达后校验token:如果有更新的请求已经发出,丢弃本次响应 + if (currentToken !== aiChatRequestToken) { + return + } + + // 响应到达后再次检查:如果用户已经取消,不应用AI补丁 + const status = getNodeAIStatus(currentSchema.id) + if (!status || status.state !== 'loading') { + return + } + + // AI运行完:设置chatContent、aiModifiedNodeData,修改画布schema为AI的schema + // 应用失败则取消loading,避免UI永久转圈 + if (!applyAIPatches(currentSchema.id, response, content)) { + cancelNodeAILoading(currentSchema.id) + } + } catch (error) { + // 请求被取消时不再应用补丁 + if (error.name === 'AbortError' || error.name === 'CanceledError') { + return + } + // 其他错误:取消loading状态,避免UI永久转圈 + cancelNodeAILoading(currentSchema.id) + } + } + + // AI加载取消处理 + const handleAILoadingCancel = () => { + const currentSchema = getCurrent().schema + if (!currentSchema?.id) { + return + } + + // 中止正在进行的AI请求 + if (aiChatAbortController) { + aiChatAbortController.abort() + aiChatAbortController = null + // 递增token,使任何未完成的请求响应失效 + aiChatRequestToken++ + } + + // 取消加载状态 + cancelNodeAILoading(currentSchema.id) + } + + // 刷新AI操作(重新生成) + // 逻辑:修改画布节点schema为originalNodeData,设置aiModifiedNodeData为空,重新发起请求 + const handleAIRefresh = async () => { + const currentSchema = getCurrent().schema + if (!currentSchema?.id) { + return + } + + const nodeId = currentSchema.id + const currentAIStatus = getNodeAIStatus(nodeId) + if (!currentAIStatus) { + return + } + + // 恢复画布节点schema为originalNodeData,同步重建nodesMap + if (currentAIStatus.originalNodeData) { + const { restoreNodeSubtree } = useCanvas() + restoreNodeSubtree(nodeId, deepClone(currentAIStatus.originalNodeData)) + useMessage().publish({ topic: 'schemaChange', data: { nodeId } }) + } + + // 设置aiModifiedNodeData为空 + updateNodeAIStatus(nodeId, { + aiModifiedNodeData: undefined + }) + + // 重新进入加载状态 + startNodeAILoading(nodeId, 'AI正在重新生成...') + + // 使用上次的聊天消息重新发起请求 + const chatContent = currentAIStatus.chatContent + if (!chatContent) { + cancelNodeAILoading(nodeId) + return + } + + try { + const params = await buildAIChatRequest(chatContent) + // 创建新的AbortController用于重新生成的请求,递增token防止响应竞争 + const refreshToken = ++aiChatRequestToken + aiChatAbortController = new AbortController() + const response = await chat(params, aiChatAbortController.signal) + + // 响应到达后校验token:如果有更新的请求已经发出,丢弃本次响应 + if (refreshToken !== aiChatRequestToken) { + return + } + + // 响应到达后检查是否已被取消 + const status = getNodeAIStatus(nodeId) + if (!status || status.state !== 'loading') { + return + } + + // AI运行完操作和 handleAIChatComplete 一样,应用失败则取消loading + if (!applyAIPatches(nodeId, response, chatContent)) { + cancelNodeAILoading(nodeId) + } + } catch (error) { + // 请求被取消时不做额外处理 + if (error.name === 'AbortError' || error.name === 'CanceledError') { + return + } + cancelNodeAILoading(nodeId) + } + } + + // 确认AI操作 + const handleAIConfirm = () => { + const currentSchema = getCurrent().schema + if (!currentSchema?.id) { + return + } + + confirmNodeAIAction(currentSchema.id) + } + + // 取消AI操作 + const handleAICancel = () => { + const currentSchema = getCurrent().schema + if (!currentSchema?.id) { + return + } + + cancelNodeAIAction(currentSchema.id) + } + return { remove, moveUp, @@ -646,11 +956,22 @@ export default { showQuickAction, showPopover, showToParent, + showAIPopover, activeSetting, isModal, onMousedown, labelStyle, - labelRef + labelRef, + openAIHelper, + shouldShowAIChat, + shouldShowAILoading, + shouldShowAIConfirm, + closeAIHelper, + handleAIChatComplete, + handleAILoadingCancel, + handleAIConfirm, + handleAICancel, + handleAIRefresh } } } @@ -942,4 +1263,34 @@ export default { cursor: se-resize; } } + +.ai-helper { + position: relative; + .ai-component, + .ai-component-loading { + position: absolute; + right: 0; + width: 360px; + opacity: 0; + transform: translateY(-10px); + animation: slideIn 0.2s ease-in-out forwards; + } + .ai-component-loading { + width: 270px; + } +} +@keyframes slideIn { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(10px); + } +} +.ai-popper.ai-popper.tiny-popper.tiny-popover { + padding: 0; + border-radius: 40px; +} diff --git a/packages/canvas/container/src/composables/useAIChat.ts b/packages/canvas/container/src/composables/useAIChat.ts new file mode 100644 index 0000000000..f3cac5d227 --- /dev/null +++ b/packages/canvas/container/src/composables/useAIChat.ts @@ -0,0 +1,701 @@ +/** + * Copyright (c) 2023 - present TinyEngine Authors. + * Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd. + * + * Use of this source code is governed by an MIT-style license. + * + * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, + * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR + * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. + * + */ + +import { utils } from '@opentiny/tiny-engine-utils' +import * as jsonpatch from 'fast-json-patch' +import { jsonrepair } from 'jsonrepair' +import { + useCanvas, + useMaterial, + getMetaApi, + META_SERVICE, + useMessage, + useHistory +} from '@opentiny/tiny-engine-meta-register' +import type { NodeAIStatus } from '../../../DesignCanvas/src/api/types' +import { search, fetchAssets } from '../services/agentServices' +import { getCurrent } from '../container' + +const { deepClone } = utils + +// ==================== AI助手状态管理 ==================== + +const updateNodeAIStatus = (nodeId: string, aiStatus: Partial) => { + const { pageState } = useCanvas() + const { publish } = useMessage() + + if (!pageState.aiNodesStatus[nodeId]) { + pageState.aiNodesStatus[nodeId] = { + state: 'hidden', // 默认隐藏 + aiContext: null, + lastAIAction: '', + aiHistory: [] + } + } + + Object.assign(pageState.aiNodesStatus[nodeId], aiStatus) + + // 发布状态更新事件 + publish({ topic: 'nodeAIStatusUpdate', data: { nodeId, aiStatus: pageState.aiNodesStatus[nodeId] } }) +} + +const getNodeAIStatus = (nodeId: string): NodeAIStatus | null => { + const { pageState } = useCanvas() + return pageState.aiNodesStatus[nodeId] || null +} + +// 添加AI操作历史记录 +const addNodeAIActionHistory = (nodeId: string, action: string, content: any) => { + const currentStatus = getNodeAIStatus(nodeId) + if (!currentStatus) { + updateNodeAIStatus(nodeId, { + state: 'hidden', + aiHistory: [{ timestamp: Date.now(), action, content }] + }) + return + } + + const aiHistory = currentStatus.aiHistory || [] + aiHistory.push({ timestamp: Date.now(), action, content }) + + updateNodeAIStatus(nodeId, { + aiHistory, + lastAIAction: action + }) +} + +// 打开AI助手聊天界面 +const openNodeAIChat = (nodeId: string, initialContent: string = '') => { + updateNodeAIStatus(nodeId, { + state: 'chat', + collapsed: false, + chatContent: initialContent, + lastAIAction: 'open_chat' + }) + + addNodeAIActionHistory(nodeId, 'open_chat', { + timestamp: Date.now(), + initialContent + }) +} + +// 关闭AI助手 +const closeNodeAIHelper = (nodeId: string) => { + updateNodeAIStatus(nodeId, { + state: 'hidden', + lastAIAction: 'close' + }) + + addNodeAIActionHistory(nodeId, 'close', { + timestamp: Date.now() + }) +} + +// 确认AI助手操作(采纳) +// 逻辑:设置originalNodeData为AI修改后的schema,设置aiModifiedNodeData为空 +const confirmNodeAIAction = (nodeId: string) => { + const currentStatus = getNodeAIStatus(nodeId) + if (!currentStatus || currentStatus.state !== 'confirm') { + return + } + + // 采纳后直接回到hidden,completed无对应UI,避免需要点击两次才能重新打开 + updateNodeAIStatus(nodeId, { + state: 'hidden', + collapsed: false, + originalNodeData: deepClone(currentStatus.aiModifiedNodeData), + aiModifiedNodeData: undefined, + lastAIAction: 'confirm' + }) +} + +// 取消AI助手操作 +// 逻辑:设置aiModifiedNodeData为空,修改画布节点schema为originalNodeData +const cancelNodeAIAction = (nodeId: string) => { + const currentStatus = getNodeAIStatus(nodeId) + if (!currentStatus) { + return + } + + // 恢复画布节点schema为originalNodeData,同步重建nodesMap + if (currentStatus.originalNodeData && currentStatus.state === 'confirm') { + const { restoreNodeSubtree } = useCanvas() + const { publish } = useMessage() + restoreNodeSubtree(nodeId, deepClone(currentStatus.originalNodeData)) + publish({ topic: 'schemaChange', data: { nodeId } }) + } + + const newState = currentStatus.chatContent ? 'chat' : 'hidden' + + updateNodeAIStatus(nodeId, { + state: newState, + collapsed: false, + aiModifiedNodeData: undefined, + lastAIAction: 'cancel' + }) +} + +/** + * 设置AI修改后的节点数据(AI运行完调用) + * @param nodeId 节点ID + * @param aiModifiedNodeData AI修改后的节点数据 + */ +const setNodeAIModifiedData = (nodeId: string, aiModifiedNodeData: any) => { + const currentAIStatus = getNodeAIStatus(nodeId) + if (!currentAIStatus) { + return + } + + updateNodeAIStatus(nodeId, { + aiModifiedNodeData: deepClone(aiModifiedNodeData) + }) +} + +/** + * 采纳AI修改 + * 逻辑:设置originalNodeData为AI修改后的schema,设置aiModifiedNodeData为空 + * @param nodeId 节点ID + */ +const adoptNodeAIModification = (nodeId: string) => { + const currentAIStatus = getNodeAIStatus(nodeId) + if (!currentAIStatus || currentAIStatus.state !== 'confirm') { + return false + } + + updateNodeAIStatus(nodeId, { + state: 'completed', + originalNodeData: deepClone(currentAIStatus.aiModifiedNodeData), + aiModifiedNodeData: undefined + }) + + return true +} + +/** + * 拒绝AI修改 + * 逻辑:设置aiModifiedNodeData为空,修改画布节点schema为originalNodeData + * @param nodeId 节点ID + */ +const rejectNodeAIModification = (nodeId: string) => { + const currentAIStatus = getNodeAIStatus(nodeId) + if (!currentAIStatus || currentAIStatus.state !== 'confirm') { + return false + } + + // 恢复画布节点schema为originalNodeData,同步重建nodesMap + if (currentAIStatus.originalNodeData) { + const { restoreNodeSubtree } = useCanvas() + const { publish } = useMessage() + restoreNodeSubtree(nodeId, deepClone(currentAIStatus.originalNodeData)) + publish({ topic: 'schemaChange', data: { nodeId } }) + } + + const newState = currentAIStatus.chatContent ? 'chat' : 'hidden' + + updateNodeAIStatus(nodeId, { + state: newState, + aiModifiedNodeData: undefined + }) + + return true +} + +/** + * 重置节点AI采纳状态 + * @param nodeId 节点ID + */ +const resetNodeAIAdoptionStatus = (nodeId: string) => { + const currentAIStatus = getNodeAIStatus(nodeId) + if (currentAIStatus) { + updateNodeAIStatus(nodeId, { + originalNodeData: undefined, + aiModifiedNodeData: undefined + }) + } +} + +/** + * 检查节点是否有待处理的AI修改 + * @param nodeId 节点ID + */ +const hasNodePendingAIModification = (nodeId: string): boolean => { + const aiStatus = getNodeAIStatus(nodeId) + return aiStatus?.state === 'confirm' +} +// ==================== AI助手状态函数 ==================== + +// 获取当前节点是否应该显示AI聊天界面 +const shouldShowNodeAIChat = (nodeId: string): boolean => { + const status = getNodeAIStatus(nodeId) + return status?.state === 'chat' && !status?.collapsed +} + +// 获取当前节点是否应该显示确认弹窗 +const shouldShowNodeAIConfirm = (nodeId: string): boolean => { + const status = getNodeAIStatus(nodeId) + return status?.state === 'confirm' && !status?.collapsed +} + +// 开始AI加载状态 +const startNodeAILoading = (nodeId: string, loadingMessage: string = 'AI处理中...') => { + updateNodeAIStatus(nodeId, { + state: 'loading', + collapsed: false, + lastAIAction: 'start_loading', + aiContext: { + loadingMessage, + startTime: Date.now() + } + }) + + addNodeAIActionHistory(nodeId, 'start_loading', { + timestamp: Date.now(), + loadingMessage + }) +} + +// 完成AI加载,进入确认状态 +const completeNodeAILoading = (nodeId: string) => { + updateNodeAIStatus(nodeId, { + state: 'confirm', + collapsed: false, + lastAIAction: 'complete_loading' + }) + + addNodeAIActionHistory(nodeId, 'complete_loading', { + timestamp: Date.now() + }) +} + +// 取消AI加载 +const cancelNodeAILoading = (nodeId: string) => { + const currentStatus = getNodeAIStatus(nodeId) + if (!currentStatus || currentStatus.state !== 'loading') { + return + } + + // 返回到聊天状态或隐藏状态 + const newState = currentStatus.chatContent ? 'chat' : 'hidden' + + updateNodeAIStatus(nodeId, { + state: newState, + collapsed: false, + aiContext: undefined, + lastAIAction: 'cancel_loading' + }) + + addNodeAIActionHistory(nodeId, 'cancel_loading', { + timestamp: Date.now(), + previousState: currentStatus.state, + loadingDuration: Date.now() - (currentStatus.aiContext?.startTime || Date.now()) + }) +} + +// 获取当前节点是否应该显示AI加载状态 +const shouldShowNodeAILoading = (nodeId: string): boolean => { + const status = getNodeAIStatus(nodeId) + return status?.state === 'loading' && !status?.collapsed +} + +/** + * 逐个解析 JSON Patch 数组中的顶级 patch 对象 + * 当整个数组因括号不匹配等原因无法解析时,通过顶层 `{"op":` 模式分割后分别解析 + * 对每个单独的对象尝试 JSON.parse → jsonrepair → 修复多余括号 + */ +const parseIndividualPatches = (jsonStr: string): any[] => { + const patches: any[] = [] + + // 移除外层数组的 [ ] 包裹 + let str = jsonStr.trim() + if (str.startsWith('[')) str = str.slice(1) + if (str.endsWith(']')) str = str.slice(0, -1) + + // 通过顶层 {"op": 模式分割各个 patch 对象 + const segments: string[] = [] + let depth = 0 + let inString = false + let escape = false + let segStart = -1 + + for (let i = 0; i < str.length; i++) { + const ch = str[i] + + if (escape) { + escape = false + continue + } + if (ch === '\\' && inString) { + escape = true + continue + } + if (ch === '"') { + inString = !inString + continue + } + if (inString) continue + + if (ch === '{') { + if (depth === 0) segStart = i + depth++ + } else if (ch === '}') { + depth-- + if (depth === 0 && segStart >= 0) { + segments.push(str.slice(segStart, i + 1)) + segStart = -1 + } + } + } + + // 对每个 segment 尝试解析,逐步增强容错 + for (const seg of segments) { + let patch = null + try { + patch = JSON.parse(seg) + } catch { + try { + patch = JSON.parse(jsonrepair(seg)) + } catch { + // 尝试修复多余的尾部 } + // 找到最后一个合法的 } 位置(通过从后往前逐步移除多余的 }) + let fixed = seg + for (let trim = 0; trim < 5; trim++) { + fixed = fixed.replace(/\}(\}*)$/, '$1') // 移除最末尾的一个 } + try { + patch = JSON.parse(fixed) + break + } catch { + // 继续尝试 + } + } + } + } + if (patch && patch.op && patch.path) { + patches.push(patch) + } + } + + return patches +} + +const findJsonPatchPath = (node, targetId, path = []) => { + if (!node || typeof node !== 'object') return null + + if (node.id === targetId) { + return '/' + path.join('/') + } + + if (Array.isArray(node.children)) { + for (let i = 0; i < node.children.length; i++) { + const result = findJsonPatchPath(node.children[i], targetId, [...path, 'children', i]) + if (result) return result + } + } + + // 如果不是数组也不是目标,继续搜索其他属性 + for (const key in node) { + if (key !== 'children' && Object.hasOwn(node, key)) { + const value = node[key] + if (value && typeof value === 'object') { + const result = findJsonPatchPath(value, targetId, [...path, key]) + if (result) return result + } + } + } + + return null +} + +/** + * 解析 AI 返回的 JSON Patch 字符串,逐步增强容错: + * 1. 剥离 Markdown 代码块包裹 + * 2. 直接 JSON.parse + * 3. 修复未转义换行符后再 parse + * 4. jsonrepair 修复 + * 5. 逐个 patch 解析(跳过损坏的单个 patch) + */ +const parseJsonPatches = (content: string): any[] | null => { + let jsonStr = content + // 剥离 Markdown 代码块 + const codeBlockMatch = jsonStr.match(/```(?:json|schema)?([\s\S]*?)```/) + if (codeBlockMatch) { + jsonStr = codeBlockMatch[1].trim() + } + + let patches: any[] = [] + try { + // 策略1:直接解析 + try { + patches = JSON.parse(jsonStr) + } catch { + // 策略2:修复 JSON 字符串值中未转义的换行符 + try { + const fixedStr = jsonStr.replace( + /"((?:[^"\\]|\\.)*)"/g, + (match, inner) => '"' + inner.replace(/\n/g, '\\n').replace(/\r/g, '\\r') + '"' + ) + patches = JSON.parse(fixedStr) + } catch { + // 策略3:使用 jsonrepair 修复 + try { + patches = JSON.parse(jsonrepair(jsonStr)) + } catch { + // 策略4:逐个 patch 解析 — AI 常在深层嵌套的 children 中产生多余的括号, + // 导致整个数组解析失败。逐个提取顶级 patch 对象分别解析,跳过损坏的。 + patches = parseIndividualPatches(jsonStr) + } + } + } + } catch (error) { + return null + } + + if (!Array.isArray(patches)) { + patches = [patches] + } + return patches +} + +/** + * 辅助函数:根据路径段从对象中安全取值 + */ +const getValueBySegments = (obj: any, segments: string[]): any => { + return segments.reduce((o, key) => (o !== null ? o[key] : undefined), obj) +} + +/** + * 辅助函数:将路径段拼接为 JSON Pointer 格式(以 / 开头) + */ +const toPointer = (segments: string[]): string => '/' + segments.filter(Boolean).join('/') + +/** + * 将 JSON Patch 数组应用到页面 schema 上 + * 按操作类型分步应用:先 replace/remove,再 add,最后其他 + * add 操作会自动处理:目标数组不存在时初始化、索引越界时追加到末尾 + * @param patches JSON Patch 数组 + * @param pageSchema 当前页面 schema + * @param parentPath 当前节点在 schema 中的路径 + * @returns 应用后的新 schema + */ +const applyPatchesToSchema = (patches: any[], pageSchema: object, parentPath: string): object => { + // 分离操作类型 + const replacePatches = patches.filter((p) => p.op === 'replace' || p.op === 'remove') + const addPatches = patches.filter((p) => p.op === 'add') + const otherPatches = patches.filter((p) => p.op !== 'replace' && p.op !== 'remove' && p.op !== 'add') + + // 先应用 replace/remove 操作 + let newSchema = replacePatches.reduce((acc, patch) => { + try { + const fullPatch = { + ...patch, + path: parentPath + patch.path + } + return jsonpatch.applyPatch(acc, [fullPatch], false, false).newDocument + } catch (error) { + return acc + } + }, pageSchema) + + // 再应用 add 操作 + // 需要处理的情况: + // 1. 目标数组不存在 → 先初始化空数组,再追加 + // 2. 索引超出数组长度 → 降级为追加到末尾(/-) + // 3. 最后一段不是数字索引且目标是数组 → 追加到末尾(/-) + newSchema = addPatches.reduce((acc, patch) => { + try { + const pathSegments = patch.path.split('/').filter(Boolean) + const lastSegment = pathSegments[pathSegments.length - 1] + + if (!lastSegment) { + return acc + } + + const parentSegments = pathSegments.slice(0, -1) + const fullParentSegments = (parentPath + '/' + parentSegments.join('/')).split('/').filter(Boolean) + let parentValue = getValueBySegments(acc, fullParentSegments) + let fixedPath = patch.path + + // 父路径对应的值不是数组但路径暗示要往数组中插入(如 /children/0), + // 需要先初始化空数组 + if (!Array.isArray(parentValue) && /^\d+$/.test(lastSegment)) { + const arrayPath = toPointer(parentPath.split('/').filter(Boolean).concat(parentSegments)) + try { + const patched = jsonpatch.applyPatch( + acc, + [{ op: 'add', path: arrayPath, value: [] }], + false, + false + ).newDocument + acc = patched + parentValue = getValueBySegments(acc, fullParentSegments) + } catch { + // 路径已存在或初始化失败,尝试继续 + } + } + + // 根据目标数组的状态修正路径 + if (Array.isArray(parentValue)) { + const index = Number(lastSegment) + if (Number.isNaN(index)) { + fixedPath = toPointer(pathSegments) + '/-' + } else if (index >= parentValue.length) { + fixedPath = toPointer(parentSegments) + '/-' + } + } + + const fullPatch = { + ...patch, + path: parentPath + fixedPath + } + return jsonpatch.applyPatch(acc, [fullPatch], false, false).newDocument + } catch (error) { + return acc + } + }, newSchema) + + // 最后应用其他操作(move, copy, test 等) + newSchema = otherPatches.reduce((acc, patch) => { + try { + const fullPatch = { + ...patch, + path: parentPath + patch.path + } + return jsonpatch.applyPatch(acc, [fullPatch], false, false).newDocument + } catch (error) { + return acc + } + }, newSchema) + + return newSchema +} + +/** + * 应用AI返回的JSON Patch到页面schema,完成画布更新 + * 逻辑:设置chatContent、设置aiModifiedNodeData为AI修改后的节点schema、修改画布节点schema为AI的schema + * @param nodeId 当前节点ID + * @param chatResponse AI聊天接口返回的响应对象 + * @param chatContent 用户发送的聊天消息 + * @returns 应用成功返回 true,失败返回 false + */ +const applyAIPatches = (nodeId: string, chatResponse: any, chatContent?: string): boolean => { + if (!chatResponse?.choices?.[0]?.message?.content) { + return false + } + + const { fixMethods, schemaAutoFix } = getMetaApi('engine.service.robot') + const { getPageSchema, getNode, updatePageSchema, setSaved } = useCanvas() + + const content = chatResponse.choices[0].message.content + const validJsonPatches = parseJsonPatches(content) + if (!validJsonPatches) { + return false + } + + const parentPath = findJsonPatchPath(getPageSchema(), nodeId) + const newSchema = applyPatchesToSchema(validJsonPatches, getPageSchema(), parentPath) + + fixMethods(newSchema.methods) + schemaAutoFix(newSchema.children) + + // 使用 updatePageSchema 更新画布(保留 nodesStatus 不清空) + updatePageSchema(newSchema) + + // 设置 AI 状态:chatContent、aiModifiedNodeData + const modifiedNode = getNode(nodeId) + const modifiedNodeData = modifiedNode ? deepClone(modifiedNode) : validJsonPatches[0]?.value + + updateNodeAIStatus(nodeId, { + state: 'confirm', + collapsed: false, + chatContent, + aiModifiedNodeData: modifiedNodeData + }) + + setSaved(false) + useHistory().addHistory() + completeNodeAILoading(nodeId) + return true +} + +// ==================== AI聊天请求构建 ==================== + +/** + * 构建AI聊天请求参数 + * @param content 用户输入的消息文本 + * @returns 请求参数对象 + */ +const buildAIChatRequest = async (content: string) => { + const { getRobotServiceOptions, formatComponents, getAgentSystemPrompt, getSelectedModelInfo } = + getMetaApi('engine.service.robot') + + const currentSchema = getCurrent().schema + const modelInfo = getSelectedModelInfo() + let referenceContext = '' + let imageAssets: any[] = [] + + if (getRobotServiceOptions()?.enableRagContext) { + referenceContext = await search(content) + } + if (getRobotServiceOptions()?.enableResourceContext) { + const appId = getMetaApi(META_SERVICE.GlobalService).getBaseInfo().id + imageAssets = await fetchAssets(appId) + } + + const { materialState, getComponentDetail } = useMaterial() + const components = formatComponents(materialState.components, getComponentDetail) + const messages = [ + { role: 'system', content: getAgentSystemPrompt(components, currentSchema, referenceContext, imageAssets) }, + { role: 'user', content: [{ type: 'text', text: content }] } + ] + + return { + body: { + baseUrl: modelInfo.baseUrl, + model: modelInfo.model, + apiKey: modelInfo.apiKey, + messages + }, + headers: { + Authorization: `Bearer ${modelInfo.apiKey}`, + 'Content-Type': 'application/json' + } + } +} + +export default function () { + return { + // AI助手状态管理 + updateNodeAIStatus, + getNodeAIStatus, + addNodeAIActionHistory, + // AI助手状态机函数 + openNodeAIChat, + closeNodeAIHelper, + startNodeAILoading, + completeNodeAILoading, + cancelNodeAILoading, + confirmNodeAIAction, + cancelNodeAIAction, + shouldShowNodeAIChat, + shouldShowNodeAILoading, + shouldShowNodeAIConfirm, + // 节点级AI采纳状态管理 + setNodeAIModifiedData, + adoptNodeAIModification, + rejectNodeAIModification, + resetNodeAIAdoptionStatus, + hasNodePendingAIModification, + findJsonPatchPath, + applyAIPatches, + // AI聊天请求构建 + buildAIChatRequest + } +} diff --git a/packages/canvas/container/src/services/agentServices.ts b/packages/canvas/container/src/services/agentServices.ts new file mode 100644 index 0000000000..3f9361cb1d --- /dev/null +++ b/packages/canvas/container/src/services/agentServices.ts @@ -0,0 +1,73 @@ +/** + * Copyright (c) 2023 - present TinyEngine Authors. + * Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd. + * + * Use of this source code is governed by an MIT-style license. + * + * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, + * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR + * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. + * + */ + +import { getMetaApi, META_SERVICE } from '@opentiny/tiny-engine-meta-register' + +/** + * AI搜索功能 + * @param content 搜索内容 + * @returns 搜索结果字符串 + */ +export const search = async (content: string): Promise => { + let result = '' + const MAX_SEARCH_LENGTH = 8000 + + try { + const res = await getMetaApi(META_SERVICE.Http).post('app-center/api/ai/search', { content }) + + res.forEach((item: { content: string }) => { + if (result.length + item.content.length > MAX_SEARCH_LENGTH) { + return + } + result += item.content + }) + } catch (error) { + return '' + } + + return result +} + +/** + * 获取资源列表 + * @returns 格式化的资源列表 + */ +export const fetchAssets = async (appId: string) => { + try { + const res = (await getMetaApi(META_SERVICE.Http).get(`material-center/api/resource/find/${appId}`)) || [] + return res + .map((group: any) => group.resources) + .flat() + .filter((item: any) => item.description) + .map((item: any) => ({ + url: item.resourceUrl, + describe: item.description + })) + } catch (error) { + return [] + } +} + +export const chat = async (params, signal?: AbortSignal) => { + const response = await getMetaApi(META_SERVICE.Http).request({ + url: 'app-center/api/ai/chat', + method: 'POST', + headers: { + 'Content-Type': 'application/json', + ...params.headers + }, + data: params.body, + signal + }) + + return response +} diff --git a/packages/canvas/package.json b/packages/canvas/package.json index 092e104b35..d3ed66ef19 100644 --- a/packages/canvas/package.json +++ b/packages/canvas/package.json @@ -1,6 +1,6 @@ { "name": "@opentiny/tiny-engine-canvas", - "version": "2.10.0-rc.0", + "version": "2.10.0", "publishConfig": { "access": "public" }, @@ -42,6 +42,11 @@ "@opentiny/tiny-engine-i18n-host": "workspace:*", "@opentiny/tiny-engine-meta-register": "workspace:*", "@opentiny/tiny-engine-utils": "workspace:*", + "@opentiny/tiny-robot": "0.4.0", + "@opentiny/tiny-robot-kit": "0.4.0", + "@opentiny/tiny-robot-svgs": "0.4.0", + "fast-json-patch": "~3.1.1", + "jsonrepair": "3.13.0", "@vue/babel-plugin-jsx": "^1.2.5", "@vue/shared": "^3.3.4", "@vueuse/core": "^9.6.0", diff --git a/packages/common/component/LifeCycles.vue b/packages/common/component/LifeCycles.vue index 8dcde96417..2bfa55fa6a 100644 --- a/packages/common/component/LifeCycles.vue +++ b/packages/common/component/LifeCycles.vue @@ -277,7 +277,7 @@ export default { .life-cycle-tips { color: var(--te-component-common-text-color-weaken); margin: 4px 0 0; - height: 16px; + height: 30px; line-height: 16px; } .life-cycle-content-list { diff --git a/packages/common/composable/generateCode/index.ts b/packages/common/composable/generateCode/index.ts index 505a9e1acb..0b27a5daef 100644 --- a/packages/common/composable/generateCode/index.ts +++ b/packages/common/composable/generateCode/index.ts @@ -1,6 +1,7 @@ import { generateApp, type IAppSchema } from '@opentiny/tiny-engine-dsl-vue' import * as dslVue from '@opentiny/tiny-engine-dsl-vue' import { getMergeMeta } from '@opentiny/tiny-engine-meta-register' +import { formatString } from '../../js/ast' import defaultPrettierConfig from '../../js/config-files/prettierrc' // 应用出码默认配置 @@ -42,7 +43,7 @@ const generateAppCode = async (appSchema: IAppSchema, options = {}) => { const { parseRequiredBlocks, genSFCWithDefaultPlugin } = dslVue as any const generatePageCode = (...args: any[]) => { - return genSFCWithDefaultPlugin(...args) + return formatString(genSFCWithDefaultPlugin(...args), 'vue') } /** diff --git a/packages/common/js/ast.ts b/packages/common/js/ast.ts index 55ff615e7d..0c4cc40051 100644 --- a/packages/common/js/ast.ts +++ b/packages/common/js/ast.ts @@ -38,12 +38,23 @@ export const string2Ast = (string = ''): BabelAst => export const ast2String = (ast: GeneratorInput): string => generate(ast, { retainLines: true }).code // 将 AST 再转回字符串 type FormatterFn = (input: string) => string -type SupportedLanguage = 'json' | 'typescript' | 'javascript' | 'html' | 'css' +type SupportedLanguage = 'json' | 'typescript' | 'javascript' | 'html' | 'css' | 'vue' | 'less' +type SupportedPrettierParser = 'json' | 'babel' | 'babel-ts' | 'html' | 'css' | 'less' | 'vue' -const formatScript: FormatterFn = (string) => { +const PRETTIER_PLUGINS = [parserBabel, parseCss, parserHtml] + +const formatWithParser = (string: string, parser: SupportedPrettierParser, options: PrettierOptions = {}): string => + prettier.format(string, { + parser, + plugins: PRETTIER_PLUGINS, + ...basePrettierConfig, + ...options + }) + +const formatScript = (string: string, parser: 'babel' | 'babel-ts' = 'babel'): string => { let newStr = string const options: PrettierOptions = { - parser: 'babel', + parser, plugins: [parserBabel], ...basePrettierConfig } @@ -72,34 +83,49 @@ const formatScript: FormatterFn = (string) => { return newStr } -const formatJson: FormatterFn = (string) => - prettier.format(string, { - parser: 'json', - plugins: [parserBabel], - trailingComma: 'es5', - ...basePrettierConfig - }) +const formatJson: FormatterFn = (string) => formatWithParser(string, 'json') -const formatHtml: FormatterFn = (string) => - prettier.format(string, { - parser: 'html', - plugins: [parserBabel, parserHtml], - ...basePrettierConfig - }) +const formatHtml: FormatterFn = (string) => formatWithParser(string, 'html') -const formatCss: FormatterFn = (string) => - prettier.format(string, { - parser: 'css', - plugins: [parseCss], - ...basePrettierConfig - }) +const formatCss: FormatterFn = (string) => formatWithParser(string, 'css') + +const formatVue: FormatterFn = (string) => formatWithParser(string, 'vue') + +const formatLess: FormatterFn = (string) => formatWithParser(string, 'less') const formatterMap: Record = { json: formatJson, - typescript: formatScript, + typescript: (str) => formatScript(str, 'babel-ts'), javascript: formatScript, html: formatHtml, - css: formatCss + css: formatCss, + vue: formatVue, + less: formatLess +} + +const parserMap: Record = { + json: 'json', + js: 'babel', + jsx: 'babel', + mjs: 'babel', + cjs: 'babel', + ts: 'babel-ts', + tsx: 'babel-ts', + css: 'css', + less: 'less', + html: 'html', + vue: 'vue' +} + +export const getPrettierParserByFileName = (fileName = ''): SupportedPrettierParser | undefined => { + const pureFileName = fileName.split('?')[0].split('#')[0].toLowerCase() + const extension = pureFileName.split('.').at(-1) + + if (!extension || extension === pureFileName) { + return undefined + } + + return parserMap[extension] } export const formatString = (str: string, language: string): string => { @@ -115,6 +141,27 @@ export const formatString = (str: string, language: string): string => { return result } +export const formatStringByFileName = (str: string, fileName: string): string => { + const parser = getPrettierParserByFileName(fileName) + + if (!parser) { + return str + } + + try { + if (parser === 'babel' || parser === 'babel-ts') { + return formatScript(str, parser) + } + + return formatWithParser(str, parser) + } catch (error) { + const printer: Console = console + printer.log(error) + + return str + } +} + export { parse, parseExpression, traverse, generate } export const includedExpression = (code: string, expression: string): boolean => { diff --git a/packages/common/js/import-map.json b/packages/common/js/import-map.json index 347291c38b..1fc71a5cef 100644 --- a/packages/common/js/import-map.json +++ b/packages/common/js/import-map.json @@ -9,7 +9,7 @@ "@vueuse/shared": "${VITE_CDN_DOMAIN}/@vueuse/shared${versionDelimiter}9.6.0${fileDelimiter}/index.mjs", "axios": "${VITE_CDN_DOMAIN}/axios${versionDelimiter}1.0.0${fileDelimiter}/dist/esm/axios.js", "@opentiny/tiny-engine-i18n-host": "${VITE_CDN_DOMAIN}/@opentiny/tiny-engine-i18n-host${versionDelimiter}^2${fileDelimiter}/dist/lowcode-design-i18n-host.es.js", - "@opentiny/tiny-engine-builtin-component": "${VITE_CDN_DOMAIN}/@opentiny/tiny-engine-builtin-component${versionDelimiter}^2.10.0-rc.0${fileDelimiter}/dist/index.mjs", + "@opentiny/tiny-engine-builtin-component": "${VITE_CDN_DOMAIN}/@opentiny/tiny-engine-builtin-component${versionDelimiter}^2.10.0${fileDelimiter}/dist/index.mjs", "vue-demi": "${VITE_CDN_DOMAIN}/vue-demi${versionDelimiter}0.13.11${fileDelimiter}/lib/index.mjs", "pinia": "${VITE_CDN_DOMAIN}/pinia${versionDelimiter}2.0.22${fileDelimiter}/dist/pinia.esm-browser.js", "@opentiny/vue": "${VITE_CDN_DOMAIN}/@opentiny/vue-runtime${versionDelimiter}~3.20${fileDelimiter}/dist3/tiny-vue-pc.mjs", diff --git a/packages/common/js/verification.ts b/packages/common/js/verification.ts index 32264ac2be..dccfb0d245 100644 --- a/packages/common/js/verification.ts +++ b/packages/common/js/verification.ts @@ -11,6 +11,7 @@ */ export const REGEXP_EVENT_NAME = /^[a-z]+([A-Z][a-z]*)*$/ +export const REGEXP_UPDATE_EVENT_NAME = /^onUpdate:[a-zA-Z_$][\w$]*$/ export const verifyEventName = (name: string) => REGEXP_EVENT_NAME.test(name) diff --git a/packages/common/package.json b/packages/common/package.json index ddf48bece6..062c342440 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -1,6 +1,6 @@ { "name": "@opentiny/tiny-engine-common", - "version": "2.10.0-rc.0", + "version": "2.10.0", "publishConfig": { "access": "public" }, diff --git a/packages/configurator/package.json b/packages/configurator/package.json index fc70381c73..b0bbc36bf3 100644 --- a/packages/configurator/package.json +++ b/packages/configurator/package.json @@ -1,6 +1,6 @@ { "name": "@opentiny/tiny-engine-configurator", - "version": "2.10.0-rc.0", + "version": "2.10.0", "description": "", "main": "dist/index.js", "module": "dist/index.js", diff --git a/packages/configurator/src/model-api-configurator/ModelApiConfigurator.vue b/packages/configurator/src/model-api-configurator/ModelApiConfigurator.vue index b6b4a79a01..335a50c64c 100644 --- a/packages/configurator/src/model-api-configurator/ModelApiConfigurator.vue +++ b/packages/configurator/src/model-api-configurator/ModelApiConfigurator.vue @@ -4,7 +4,7 @@ trigger="manual" v-model="isShow" :visible-arrow="false" - :popper-class="['option-popper', 'fixed-left']" + :popper-class="['option-popper', 'fixed-left', 'model-function-popper']" :offset="isSecond ? 652 : 0" width="600" > @@ -230,7 +230,7 @@ onMounted(() => { display: flex; justify-content: space-between; align-items: center; - margin: 8px 0 20px 0; + margin: 8px 16px 20px 16px; .right { svg { margin-left: 10px; @@ -286,7 +286,10 @@ onMounted(() => { .model-param-wrap { .tiny-form { - padding: 12px; + padding: 12px 28px; + } + .tiny-collapse.tiny-collapse .tiny-collapse-item { + padding: 0 12px; } } } @@ -318,3 +321,10 @@ onMounted(() => { color: var(--te-common-text-secondary); } + diff --git a/packages/configurator/src/model-configurator/ModelConfigurator.vue b/packages/configurator/src/model-configurator/ModelConfigurator.vue index 04e313e2e1..9380ec97ed 100644 --- a/packages/configurator/src/model-configurator/ModelConfigurator.vue +++ b/packages/configurator/src/model-configurator/ModelConfigurator.vue @@ -6,7 +6,7 @@ trigger="manual" v-model="isShow" :visible-arrow="false" - :popper-class="['option-popper', 'fixed-left']" + :popper-class="['option-popper', 'fixed-left', 'model-popper']" >
绑定模型数据 @@ -424,19 +424,15 @@ onMounted(() => { .model-container { width: 100%; line-height: 28px; - background-color: var(--ti-lowcode-input-bg); &:hover { cursor: pointer; } - .model-name-warp { - border: 1px solid var(--ti-lowcode-component-input-border-color); - } .meta-model-title { - color: #808080; + color: var(--te-configurator-common-text-color-weaken); } .meta-array-wrap { font-size: 12px; - border: 1px solid #dbdbdb; + border: 1px solid var(--te-configurator-common-border-color); border-radius: 4px; display: block; :deep(.tiny-search) { @@ -444,7 +440,7 @@ onMounted(() => { .tiny-search__line { border: none; border-radius: 0; - border-bottom: 1px solid var(--ti-search-input-border-color); + border-bottom: 1px solid var(--te-configurator-common-border-color); } } .meta-array-header { @@ -567,3 +563,9 @@ onMounted(() => { } } + diff --git a/packages/configurator/src/source-select-configurator/SourceSelectConfigurator.vue b/packages/configurator/src/source-select-configurator/SourceSelectConfigurator.vue index 1c27755939..ce4f341974 100644 --- a/packages/configurator/src/source-select-configurator/SourceSelectConfigurator.vue +++ b/packages/configurator/src/source-select-configurator/SourceSelectConfigurator.vue @@ -204,12 +204,11 @@ export default { .source-container { width: 100%; line-height: 28px; - background-color: var(--ti-lowcode-input-bg); .source-img-wrap { position: relative; width: 150px; height: 96px; - background-color: var(--te-common-bg-container); + background-color: var(--te-configurator-container-bg-color); img { width: 100%; height: 100%; @@ -232,7 +231,7 @@ export default { width: 70px; height: 22px; line-height: 22px; - border: 1px solid var(--te-common-bg-popover); + border: 1px solid var(--te-configurator-common-border-color); border-radius: 4px; text-align: center; color: var(--te-common-text-inverse); diff --git a/packages/configurator/src/styles/vars.less b/packages/configurator/src/styles/vars.less index d628d7fe0e..b4b2526d1f 100644 --- a/packages/configurator/src/styles/vars.less +++ b/packages/configurator/src/styles/vars.less @@ -21,6 +21,8 @@ --te-configurator-common-border-color-divider: var(--te-common-border-divider); --te-configurator-common-border-color: var(--te-common-border-default); + --te-configurator-common-panel-shadow-color: var(--te-common-shadow-panel); + --te-configurator-button-group-bg-color-active: var(--te-common-bg-prompt); --te-configurator-button-group-bg-color: var(--te-common-bg-container); diff --git a/packages/design-core/assets/chat.svg b/packages/design-core/assets/chat.svg index 29d05ff782..0d086bbb7c 100644 --- a/packages/design-core/assets/chat.svg +++ b/packages/design-core/assets/chat.svg @@ -1,13 +1,16 @@ - - - Created with Pixso. - - - - - - - - - - + + + + \ No newline at end of file diff --git a/packages/design-core/assets/generate-code.svg b/packages/design-core/assets/generate-code.svg index 9ef86cf4b8..8450940c9c 100644 --- a/packages/design-core/assets/generate-code.svg +++ b/packages/design-core/assets/generate-code.svg @@ -1,12 +1,24 @@ - - - Created with Pixso. - - - - - - - - + + + diff --git a/packages/design-core/assets/intelligent-construction.svg b/packages/design-core/assets/intelligent-construction.svg index d4d2df3d39..76110b490c 100644 --- a/packages/design-core/assets/intelligent-construction.svg +++ b/packages/design-core/assets/intelligent-construction.svg @@ -1,4 +1,16 @@ - + - - + + \ No newline at end of file diff --git a/packages/design-core/assets/more.svg b/packages/design-core/assets/more.svg new file mode 100644 index 0000000000..7b9b2c5d2e --- /dev/null +++ b/packages/design-core/assets/more.svg @@ -0,0 +1,25 @@ + + + + \ No newline at end of file diff --git a/packages/design-core/assets/nest-attempt.svg b/packages/design-core/assets/nest-attempt.svg new file mode 100644 index 0000000000..4893570e88 --- /dev/null +++ b/packages/design-core/assets/nest-attempt.svg @@ -0,0 +1,24 @@ + + + + diff --git a/packages/design-core/assets/plugin.svg b/packages/design-core/assets/plugin.svg new file mode 100644 index 0000000000..fe8fb2edc8 --- /dev/null +++ b/packages/design-core/assets/plugin.svg @@ -0,0 +1,16 @@ + + + + diff --git a/packages/design-core/assets/think.svg b/packages/design-core/assets/think.svg new file mode 100644 index 0000000000..601f51124a --- /dev/null +++ b/packages/design-core/assets/think.svg @@ -0,0 +1,16 @@ + + + + diff --git a/packages/design-core/assets/upload.svg b/packages/design-core/assets/upload.svg index a92b43d4b6..593915a246 100644 --- a/packages/design-core/assets/upload.svg +++ b/packages/design-core/assets/upload.svg @@ -1,14 +1,17 @@ - - - - - - + + + + + \ No newline at end of file diff --git a/packages/design-core/assets/workspace-menu.svg b/packages/design-core/assets/workspace-menu.svg new file mode 100644 index 0000000000..b64502f20a --- /dev/null +++ b/packages/design-core/assets/workspace-menu.svg @@ -0,0 +1,17 @@ + + + + + diff --git a/packages/design-core/package.json b/packages/design-core/package.json index 0706fa9053..02cc0c14c5 100644 --- a/packages/design-core/package.json +++ b/packages/design-core/package.json @@ -1,6 +1,6 @@ { "name": "@opentiny/tiny-engine", - "version": "2.10.0-rc.0", + "version": "2.10.0", "type": "module", "description": "TinyEngine enables developers to customize low-code platforms, build low-bit platforms online in real time, and support secondary development or integration of low-bit platform capabilities.", "homepage": "https://opentiny.design/tiny-engine", diff --git a/packages/design-core/src/login/ForgotPassword.vue b/packages/design-core/src/login/ForgotPassword.vue index e75c5037d7..29159986dd 100644 --- a/packages/design-core/src/login/ForgotPassword.vue +++ b/packages/design-core/src/login/ForgotPassword.vue @@ -52,7 +52,7 @@ - 提交 + 提交
@@ -62,7 +62,7 @@ diff --git a/packages/plugins/page/package.json b/packages/plugins/page/package.json index 5e8527504b..9aff269c7b 100644 --- a/packages/plugins/page/package.json +++ b/packages/plugins/page/package.json @@ -1,6 +1,6 @@ { "name": "@opentiny/tiny-engine-plugin-page", - "version": "2.10.0-rc.0", + "version": "2.10.0", "publishConfig": { "access": "public" }, diff --git a/packages/plugins/page/src/PageSetting.vue b/packages/plugins/page/src/PageSetting.vue index 8e3f65501a..576b908ae1 100644 --- a/packages/plugins/page/src/PageSetting.vue +++ b/packages/plugins/page/src/PageSetting.vue @@ -498,4 +498,10 @@ export default { padding: 0 12px 12px; } } + +.input-output { + :deep(.tiny-collapse-item__content) { + margin-bottom: 4px; + } +} diff --git a/packages/plugins/page/src/composable/usePage.ts b/packages/plugins/page/src/composable/usePage.ts index 44150e1467..4bb21f257b 100644 --- a/packages/plugins/page/src/composable/usePage.ts +++ b/packages/plugins/page/src/composable/usePage.ts @@ -22,6 +22,7 @@ import { useModal, useNotify, getMetaApi, + getMergeMeta, META_SERVICE } from '@opentiny/tiny-engine-meta-register' import http from '../http' @@ -115,6 +116,27 @@ export interface MaterialsOptions { } const generateCssString = (pageOptions: PageOptions, materialsOptions: MaterialsOptions) => { + const enableStructuredCss = getMergeMeta('engine.config')?.enableStructuredCss + + if (!enableStructuredCss) { + if (!pageOptions?.pageBaseStyle?.className || !pageOptions?.pageBaseStyle?.style) { + return '' + } + + const formatCssRule = (className: string, style: string) => `.${className} {\n ${style.trim()}\n}\n` + const baseStyle = `.${pageOptions.pageBaseStyle.className}{\r\n ${pageOptions.pageBaseStyle.style}\r\n}\r\n` + + if (!materialsOptions.useBaseStyle) { + return baseStyle + } + + return [ + formatCssRule(pageOptions.pageBaseStyle.className, pageOptions.pageBaseStyle.style), + formatCssRule(materialsOptions.blockBaseStyle.className, materialsOptions.blockBaseStyle.style), + formatCssRule(materialsOptions.componentBaseStyle.className, materialsOptions.componentBaseStyle.style) + ].join('\n') + } + let cssObject: Record = {} const parseStyle = (styleString: string) => { const styleObj: Record = {} diff --git a/packages/plugins/resource/package.json b/packages/plugins/resource/package.json index 13dacd47c5..290deb59fc 100644 --- a/packages/plugins/resource/package.json +++ b/packages/plugins/resource/package.json @@ -1,6 +1,6 @@ { "name": "@opentiny/tiny-engine-plugin-resource", - "version": "2.10.0-rc.0", + "version": "2.10.0", "publishConfig": { "access": "public" }, diff --git a/packages/plugins/resource/src/ResourceSetting.vue b/packages/plugins/resource/src/ResourceSetting.vue index a9f73da52e..1c6d776209 100644 --- a/packages/plugins/resource/src/ResourceSetting.vue +++ b/packages/plugins/resource/src/ResourceSetting.vue @@ -1,5 +1,11 @@