[
  {
    "path": ".eslintignore",
    "content": "dist\ngemini.js\ngeminiProxy.js"
  },
  {
    "path": ".eslintrc.js",
    "content": "module.exports = {\n  root: true,\n  env: {\n    browser: true,\n    es2021: true,\n  },\n  extends: [\n    'airbnb-base',\n    'prettier',\n    'eslint:recommended',\n    'plugin:@typescript-eslint/recommended',\n  ],\n  parser: '@typescript-eslint/parser',\n  plugins: ['prettier', '@typescript-eslint'],\n  parserOptions: {\n    ecmaVersion: 12,\n  },\n  rules: {\n    'prettier/prettier': 'error',\n    'func-names': 'off',\n    'import/prefer-default-export': 'off',\n    'no-plusplus': 'off',\n    'no-unused-vars': 'off',\n    '@typescript-eslint/no-var-requires': 'off',\n    '@typescript-eslint/no-unused-vars': 'off',\n    'max-classes-per-file': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n    'class-methods-use-this': 'off',\n    '@typescript-eslint/ban-ts-comment': 'off',\n    'import/no-unresolved': 'off',\n    'no-useless-constructor': 'off',\n    'no-empty-function': 'off',\n    'import/extensions': 'off',\n    'consistent-return': 'off',\n    'no-use-before-define': 'off',\n    'array-callback-return': 'off',\n    'no-param-reassign': 'off',\n    'no-new-func': 'off',\n    'no-empty': 'off',\n    'import/no-dynamic-require': 'off',\n    'global-require': 'off',\n    'import/no-extraneous-dependencies': 'off',\n    'no-template-curly-in-string': 'off',\n    'arrow-body-style': 'off',\n    'prefer-promise-reject-errors': 'off',\n  },\n};\n"
  },
  {
    "path": ".gitattributes",
    "content": "*.ejs linguist-language=TypeScript"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\nnode_modules/\n.ts-node\n.lowcoderc\ndist"
  },
  {
    "path": ".npmrc",
    "content": "electron_mirror=https://npmmirror.com/mirrors/electron/"
  },
  {
    "path": ".prettierignore",
    "content": ".ejs\ndist"
  },
  {
    "path": ".prettierrc.js",
    "content": "module.exports = {\n  trailingComma: 'all',\n  tabWidth: 2,\n  semi: true,\n  singleQuote: true,\n  endOfLine: 'auto',\n};\n"
  },
  {
    "path": "README.md",
    "content": "将项目 clone 到本地，安装依赖，执行 yarn build\n\n## 使用 VSCODE\n\n安装 [lowcode](https://marketplace.visualstudio.com/items?itemName=wjkang.lowcode) 插件\n\n设置同步目录为 clone 项目的目录\n\n![](https://github.com/user-attachments/assets/979aefca-445b-4805-98e8-5224f9a06067)\n\n![](https://github.com/user-attachments/assets/01f4684d-3cc5-496d-adce-91a345c8a4c8)\n\nvscode 执行如下命令\n\n![](https://github.com/user-attachments/assets/3563be5f-322d-429a-b3d7-44be3d380fbe)\n\n出现如下选项，配置成功\n\n![](https://github.com/user-attachments/assets/266b876a-bae9-409a-bbb9-f01dbd8c0637)\n\n快速创建区块\n\n![](https://github.com/user-attachments/assets/cacc892a-0834-4899-a766-f6e090abe302)\n\n\n\n以同步目录设置的代码模版和区块在所有项目里都可见，代码逻辑可以自由修改，不过分依赖 lowcode 插件内部，比如上面快速创建区块的代码： https://github.com/lowcode-scaffold/lowcode-materials/blob/master/materials/snippets/%E5%BF%AB%E9%80%9F%E5%88%9B%E5%BB%BA%E5%8C%BA%E5%9D%97/script/src/main.ts\n\n### 支持其它 LLM\n\n只要实现了 `llm/index.js` 中的 `createChatCompletion` 的方法，lowcode 插件内部的 ChatGPT 请求将会转为使用这个方法。不存在这个文件或者没有  `createChatCompletion` 方法会继续使用内部 ChatGPT 请求。https://github.com/lowcode-scaffold/lowcode-materials/blob/master/llm/index.js\n\n如果使用的 LLM 兼容 openai 的数据格式，直接通过可视化界面进行配置\n\n![image](https://github.com/user-attachments/assets/c115b70c-68f8-4479-96f4-495d4d0a1275)\n\n![image](https://github.com/user-attachments/assets/cfa2b61b-e462-40a5-aadd-710adec15b8a)\n\n![image](https://github.com/user-attachments/assets/5eb13ef1-150b-450c-9b53-018cbbdf59a1)\n\n\n## 使用 uTools\n\n### uTools 自动化脚本\n\n安装依赖后执行 yarn build，uTools 中安装自动化脚本插件，新建脚本，把 dist/utools 目录下的各个 index.js 内容复制过去就行。\n\n![image](https://github.com/user-attachments/assets/ee3cd944-850b-478b-b1e7-03fa8a79d3a2)\n\n![image](https://github.com/user-attachments/assets/3b307be1-70ab-4524-9a2d-9b19419965a4)\n\n\n部分脚本需要配合插件使用，插件下载：[lowcode-1.0.0.upxs](https://github.com/lowcode-scaffold/lowcode-materials/releases)\n\n\n一个生成特定代码的例子：\n\n![](https://github.com/user-attachments/assets/ebd19d40-1f92-49d3-ab13-aa7272ff04f9)\n\n![](https://github.com/user-attachments/assets/b0a4e635-08cf-4e09-8469-6d73c76c17d3)\n\n"
  },
  {
    "path": "buildMaterials.js",
    "content": "const path = require('path');\nconst fs = require('fs-extra');\n/**\n * @description\n * @param {string} dirPath\n * @return {string[]}\n */\nfunction getAllFiles(dirPath) {\n  const files = fs.readdirSync(dirPath);\n\n  let result = [];\n\n  // eslint-disable-next-line no-restricted-syntax\n  for (const file of files) {\n    const filePath = `${dirPath}/${file}`;\n    // eslint-disable-next-line no-await-in-loop\n    const stats = fs.statSync(filePath);\n\n    if (stats.isDirectory()) {\n      result = result.concat(getAllFiles(filePath));\n    } else {\n      result.push(filePath);\n    }\n  }\n\n  return result;\n}\n\nconst devContent = `\nrequire('ts-node').register({\n  transpileOnly: true,\n  typeCheck: false,\n  emit: false,\n  compilerHost: false, // 和 emit 一起设置为 true，会在 .ts-node 文件夹输出编译后的代码\n  cwd: __dirname, // 要输出编译后代码必须配置，否则会报错 EROFS: read-only file system, mkdir '/.ts-node'。不输出也要配置不然会出现各种奇奇怪怪的报错\n});\n// 清除缓存，保证每次修改代码后实时生效，否则要重新打开 vscode\nconst { clearCache } = require('../../../../share/clearCache.ts');\n\nclearCache(__dirname); // 调试的时候才打开，不然会很慢\nconst main = require('./src/main.ts');\nconst { context } = require('./src/context.ts');\n\n`;\n\nconst mode = process.argv[2] || 'prod';\n\nfs.removeSync(path.join(__dirname, 'dist'));\n\ngetAllFiles(path.join(__dirname, 'materials'))\n  .filter((s) => s.includes('script/index.js') && !s.includes('.ejs'))\n  .forEach((file) => {\n    const materialName = file\n      .replace(/\\\\/g, '/')\n      .replace(`${__dirname.replace(/\\\\/g, '/')}/materials/`, '')\n      .replace('/script/index.js', '');\n    const prodContent = `\nconst path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/${materialName}/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/${materialName}/script/src/context');\n\n`;\n    const content = fs.readFileSync(file).toString();\n    const exportContent = `module.exports${content.split('module.exports')[1]}`;\n    if (mode === 'prod') {\n      fs.writeFileSync(file, prodContent.trimStart() + exportContent);\n    } else {\n      fs.writeFileSync(file, devContent.trimStart() + exportContent);\n    }\n  });\n"
  },
  {
    "path": "llm/index.js",
    "content": "const vscode = require('vscode');\nconst gemini = require('../dist/share/LLM/gemini');\nconst geminiProxy = require('../dist/share/LLM/geminiProxy');\nconst openai = require('../dist/share/LLM/openai');\nconst share = require('../dist/share/utils/shareData');\n\nconst GeminiKey = 'lowcode.GeminiKey';\nconst OpenaiKey = 'lowcode.OpenaiKey';\n\nmodule.exports = {\n  /**\n   * @description 替换 lowcode 插件内部的 ChatGPT 请求，修改后需要重启对应项目 vscode\n   * @param {({\n   *   messages: { role: 'system' | 'user' | 'assistant'; content: string }[];\n   *   handleChunk?: (data: { text?: string; }) => void;\n   *   lowcodeContext: { env: { extensionContext:  any }};\n   * })} options\n   * @returns {Promise<string>}\n   */\n  createChatCompletion: async (options) => {\n    const context = options.lowcodeContext.env.extensionContext;\n    // await context.secrets.delete(GeminiKey); // 需要更新 API KEY 的时候打开\n    // let apiKey = await context.secrets.get(GeminiKey);\n    // if (!apiKey) {\n    //   vscode.window.showWarningMessage(\n    //     'Enter your API KEY to save it securely.',\n    //   );\n    //   apiKey = await setApiKey(context, GeminiKey);\n    //   if (!apiKey) {\n    //     if (options.handleChunk) {\n    //       options.handleChunk({ text: 'Please enter your api key' });\n    //     }\n    //     return 'Please enter your api key';\n    //   }\n    // }\n    // const res = await gemini.createChatCompletion({\n    //   messages: options.messages,\n    //   model: 'gemini-pro',\n    //   apiKey,\n    //   handleChunk(data) {\n    //     if (options.handleChunk) {\n    //       options.handleChunk(data);\n    //     }\n    //   },\n    //   proxyUrl: 'http://127.0.0.1:7890',\n    // });\n    // return res;\n    // const res = await geminiProxy.createChatCompletion({\n    //   messages: options.messages,\n    //   model: 'gemini-pro',\n    //   maxTokens: '4096',\n    //   handleChunk(data) {\n    //     if (options.handleChunk) {\n    //       options.handleChunk(data);\n    //     }\n    //   },\n    // });\n    // return res;\n\n    // await context.secrets.delete(OpenaiKey); // 需要更新 API KEY 的时候打开\n    // let apiKey = await context.secrets.get(OpenaiKey);\n    // if (!apiKey) {\n    //   vscode.window.showWarningMessage(\n    //     'Enter your API KEY to save it securely.',\n    //   );\n    //   apiKey = await setApiKey(context, OpenaiKey);\n    //   if (!apiKey) {\n    //     if (options.handleChunk) {\n    //       options.handleChunk({ text: 'Please enter your api key' });\n    //     }\n    //     return 'Please enter your api key';\n    //   }\n    // }\n    const config = share.oneAPIConfig() || {};\n    const res = await openai.createChatCompletion({\n      messages: options.messages,\n      hostname: config.hostname,\n      model: config.model,\n      apiKey: config.apiKey,\n      notHttps: config.notHttps,\n      apiPath: config.apiPath,\n      port: config.port,\n      handleChunk(data) {\n        if (options.handleChunk) {\n          options.handleChunk(data);\n        }\n      },\n    });\n    return res;\n  },\n};\n"
  },
  {
    "path": "lowcode-context.d.ts",
    "content": "import type vscode from 'vscode';\n\ninterface Context {\n  /**\n   * @description 模版数据\n   * @type {object}\n   */\n  model: object;\n  /**\n   * @description vscode 对象，能调用 vscode 提供的 api\n   * @type {typeof vscode}\n   */\n  vscode: typeof vscode;\n  /**\n   * @description 调用脚本的工作目录，不一定是脚本所在的项目目录\n   * @type {string}\n   */\n  workspaceRootPath: string;\n  /**\n   * @description 区块生成目录\n   * @type {string}\n   */\n  createBlockPath?: string;\n  /**\n   * @description OutputChannel\n   * @type {vscode.OutputChannel}\n   */\n  outputChannel: vscode.OutputChannel;\n  /**\n   * @description log\n   * @type {vscode.OutputChannel}\n   */\n  log: vscode.OutputChannel;\n  /**\n   * @description 调用 ChatGPT\n   */\n  createChatCompletion: (options: {\n    messages: {\n      role: 'system' | 'user' | 'assistant';\n      content: string;\n    }[];\n    handleChunk?: ((data: { text?: string }) => void) | undefined;\n    showWebview?: boolean;\n  }) => Promise<string>;\n  /**\n   * @description 当前选择的物料路径(加上物料名称)\n   * @type {string}\n   */\n  materialPath: string;\n  /**\n   * @description 一些环境变量\n   */\n  env: {\n    /**\n     * @description 等于 workspaceRootPath\n     * @type {string}\n     */\n    rootPath: string;\n    /**\n     * @description 临时工作目录\n     * @type {string}\n     */\n    tempWorkPath: string;\n    /**\n     * @description 物料路径\n     * @type {string}\n     */\n    materialsPath: string;\n    /**\n     * @description 区块路径\n     * @type {string}\n     */\n    blockMaterialsPath: string;\n    /**\n     * @description 代码片段路径\n     * @type {string}\n     */\n    snippetMaterialsPath: string;\n    /**\n     * @description 私有物料路径\n     * @type {string}\n     */\n    privateMaterialsPath: string;\n    /**\n     * @description ExtensionContext\n     * @type {vscode.ExtensionContext}\n     */\n    extensionContext: vscode.ExtensionContext;\n  };\n  /**\n   * @description lwocode 插件内部使用的一些库，暴露出来避免重复安装\n   */\n  libs: {\n    /**\n     * @description axios\n     * @type {*}\n     */\n    axios: any;\n    /**\n     * @description copy-paste\n     * @type {*}\n     */\n    copyPaste: any;\n    /**\n     * @description directory-tree\n     * @type {*}\n     */\n    dirTree: any;\n    /**\n     * @description ejs\n     * @type {*}\n     */\n    ejs: any;\n    /**\n     * @description fs-extra\n     * @type {*}\n     */\n    fsExtra: any;\n    /**\n     * @description execa\n     * @type {*}\n     */\n    execa: any;\n    /**\n     * @description glob\n     * @type {*}\n     */\n    glob: any;\n    /**\n     * @description prettier\n     * @type {*}\n     */\n    prettier: any;\n    /**\n     * @description strip-comments\n     * @type {*}\n     */\n    stripComments: any;\n    /**\n     * @description strip-json-comments\n     * @type {*}\n     */\n    stripJsonComments: any;\n    /**\n     * @description generate-schema\n     * @type {*}\n     */\n    generateSchema: any;\n    /**\n     * @description json-schema-to-typescript\n     * @type {*}\n     */\n    jsonSchemaToTypescript: any;\n    /**\n     * @description typescript-json-schema\n     * @type {*}\n     */\n    typescriptJsonSchema: any;\n    /**\n     * @description axios\n     * @type {*}\n     */\n    tar: any;\n  };\n\n  /**\n   * 剪贴板的图片，执行脚本弹框里点击确定按钮的时候获取的，不通过 webview 获取不到\n   */\n  clipboardImage?: string;\n  /**\n   * 打开 webview 获取剪贴板里的图片，base64 格式\n   */\n  getClipboardImage: () => Promise<string | undefined>;\n  /**\n   * @description 最后一次激活的 TextEditor\n   */\n  activeTextEditor?: vscode.TextEditor;\n}\nexport interface CompileContext extends Context {\n  /**\n   * @description 代码片段编译后的代码\n   * @type {string}\n   */\n  code: string;\n  /**\n   * @description 执行右键菜单时选中的文件夹\n   * @type {string}\n   */\n  explorerSelectedPath: string;\n  /** 脚本方法名，runScript 方法才有 */\n  method: string;\n  /** 脚本方法名，runScript 方法才有 */\n  script: string;\n  /** 脚本方法参数，runScript 方法才有 */\n  params: string;\n}\n\nexport interface ViewCallContext extends Context {\n  /**\n   * @description 传入的方法参数\n   * @type {string}\n   */\n  params: string;\n}\n"
  },
  {
    "path": "materials/blocks/antdv2 增删改查列表页/config/model.json",
    "content": "{\n  \"filters\": [],\n  \"columns\": [],\n  \"pagination\": {\n    \"show\": true,\n    \"page\": \"page\",\n    \"size\": \"size\",\n    \"total\": \"result.total\"\n  },\n  \"includeModifyModal\": false,\n  \"fetchName\": \"fetchTableList\",\n  \"result\": \"[\\\"result\\\"][\\\"records\\\"]\",\n  \"serviceName\": \"getTableList\"\n}"
  },
  {
    "path": "materials/blocks/antdv2 增删改查列表页/config/preview.json",
    "content": "{\n\t\"title\": \"\",\n\t\"description\": \"\",\n\t\"img\": \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\",\n\t\"category\": [],\n\t\"schema\": \"amis\",\n\t\"scripts\": [\n\t\t{\n\t\t\t\"method\": \"OCR\",\n\t\t\t\"remark\": \"OCR 识别剪贴版截图\"\n\t\t},\n\t\t{\n\t\t\t\"method\": \"initFiltersFromImage\",\n\t\t\t\"remark\": \"使用截图初始化查询条件\"\n\t\t},\n\t\t{\n\t\t\t\"method\": \"initFiltersFromText\",\n\t\t\t\"remark\": \"使用文本初始化查询条件\"\n\t\t},\n\t\t{\n\t\t\t\"method\": \"initColumnsFromText\",\n\t\t\t\"remark\": \"使用文本初始化表格\"\n\t\t},\n\t\t{\n\t\t\t\"method\": \"initColumnsFromImage\",\n\t\t\t\"remark\": \"使用截图初始化表格\"\n\t\t},\n\t\t{\n\t\t\t\"method\": \"askChatGPT\",\n\t\t\t\"remark\": \"使用 ChatGPT 翻译模版数据里的指定中文字段\"\n\t\t}\n\t]\n}"
  },
  {
    "path": "materials/blocks/antdv2 增删改查列表页/config/schema.json",
    "content": "{\n\t\"formSchema\": {\n\t\t\"schema\": {\n\t\t\t\"type\": \"page\",\n\t\t\t\"body\": [\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"form\",\n\t\t\t\t\t\"title\": \"\",\n\t\t\t\t\t\"body\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"combo\",\n\t\t\t\t\t\t\t\"label\": \"查询条件\",\n\t\t\t\t\t\t\t\"name\": \"filters\",\n\t\t\t\t\t\t\t\"multiple\": true,\n\t\t\t\t\t\t\t\"addable\": true,\n\t\t\t\t\t\t\t\"removable\": true,\n\t\t\t\t\t\t\t\"removableMode\": \"icon\",\n\t\t\t\t\t\t\t\"addBtn\": {\n\t\t\t\t\t\t\t\t\"label\": \"新增\",\n\t\t\t\t\t\t\t\t\"icon\": \"fa fa-plus\",\n\t\t\t\t\t\t\t\t\"level\": \"primary\",\n\t\t\t\t\t\t\t\t\"size\": \"sm\",\n\t\t\t\t\t\t\t\t\"id\": \"u:47ecb9e15ff1\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"items\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"key\",\n\t\t\t\t\t\t\t\t\t\"placeholder\": \"字段名\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:25b0c7b5e5a0\",\n\t\t\t\t\t\t\t\t\t\"label\": \"字段名（key）\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"label\",\n\t\t\t\t\t\t\t\t\t\"name\": \"label\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:6496cac4f4b8\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\"name\": \"component\",\n\t\t\t\t\t\t\t\t\t\"placeholder\": \"选项\",\n\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"input\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"input\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"select\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"select\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"range-picker\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"range-picker\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"id\": \"u:995915eabcca\",\n\t\t\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\t\t\"label\": \"组件\",\n\t\t\t\t\t\t\t\t\t\"value\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"后端接口查询\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"remoteFetch\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:3a46d16f89c9\",\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"visibleOn\": \"${filters[index].component==='select'}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"placeholder\",\n\t\t\t\t\t\t\t\t\t\"name\": \"placeholder\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:d7f1a8a39449\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\",\n\t\t\t\t\t\t\t\t\t\"visibleOn\": \"${filters[index].component==='select'||filters[index].component==='input'}\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"id\": \"u:186f183e9320\",\n\t\t\t\t\t\t\t\"strictMode\": false,\n\t\t\t\t\t\t\t\"syncFields\": [],\n\t\t\t\t\t\t\t\"tabsMode\": true,\n\t\t\t\t\t\t\t\"draggable\": true,\n\t\t\t\t\t\t\t\"draggableTip\": \"可拖动排序\",\n\t\t\t\t\t\t\t\"tabsStyle\": \"line\",\n\t\t\t\t\t\t\t\"tabsLabelTpl\": \"表单项${index+1}\",\n\t\t\t\t\t\t\t\"multiLine\": true,\n\t\t\t\t\t\t\t\"noBorder\": false\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"combo\",\n\t\t\t\t\t\t\t\"label\": \"表格\",\n\t\t\t\t\t\t\t\"name\": \"columns\",\n\t\t\t\t\t\t\t\"multiple\": true,\n\t\t\t\t\t\t\t\"addable\": true,\n\t\t\t\t\t\t\t\"removable\": true,\n\t\t\t\t\t\t\t\"removableMode\": \"button\",\n\t\t\t\t\t\t\t\"addBtn\": {\n\t\t\t\t\t\t\t\t\"label\": \"新增\",\n\t\t\t\t\t\t\t\t\"icon\": \"fa fa-plus\",\n\t\t\t\t\t\t\t\t\"level\": \"primary\",\n\t\t\t\t\t\t\t\t\"size\": \"sm\",\n\t\t\t\t\t\t\t\t\"id\": \"u:1e8070edc3d3\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"items\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"title\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:152dd82b82f9\",\n\t\t\t\t\t\t\t\t\t\"label\": \"title\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"dataIndex\",\n\t\t\t\t\t\t\t\t\t\"name\": \"dataIndex\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:ecc7298e0550\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"key\",\n\t\t\t\t\t\t\t\t\t\"name\": \"key\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:fbaa95c3f15d\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"width\",\n\t\t\t\t\t\t\t\t\t\"name\": \"width\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:b143127e097b\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"自定义插槽\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"slot\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:ee1ce1faee0b\",\n\t\t\t\t\t\t\t\t\t\"value\": false\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"id\": \"u:9b9fb0cf38f9\",\n\t\t\t\t\t\t\t\"strictMode\": true,\n\t\t\t\t\t\t\t\"syncFields\": [],\n\t\t\t\t\t\t\t\"tabsMode\": true,\n\t\t\t\t\t\t\t\"draggable\": true,\n\t\t\t\t\t\t\t\"draggableTip\": \"可拖动排序\",\n\t\t\t\t\t\t\t\"tabsStyle\": \"line\",\n\t\t\t\t\t\t\t\"deleteBtn\": {\n\t\t\t\t\t\t\t\t\"label\": \"删除\",\n\t\t\t\t\t\t\t\t\"level\": \"default\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"tabsLabelTpl\": \"列${index+1}\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"fieldset\",\n\t\t\t\t\t\t\t\"title\": \"分页参数\",\n\t\t\t\t\t\t\t\"collapsable\": true,\n\t\t\t\t\t\t\t\"body\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"是否分页\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"pagination.show\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:6c70041d5143\",\n\t\t\t\t\t\t\t\t\t\"value\": true,\n\t\t\t\t\t\t\t\t\t\"className\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"查询接口页数参数字段名\",\n\t\t\t\t\t\t\t\t\t\"name\": \"pagination.page\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:cbbf6853cf64\",\n\t\t\t\t\t\t\t\t\t\"value\": \"page\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"查询接口每页数据行数参数字段名\",\n\t\t\t\t\t\t\t\t\t\"name\": \"pagination.size\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:a8fae66fa927\",\n\t\t\t\t\t\t\t\t\t\"value\": \"size\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"接口返回总数据量字段 PATH\",\n\t\t\t\t\t\t\t\t\t\"name\": \"pagination.total\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:e1cd979c7ee8\",\n\t\t\t\t\t\t\t\t\t\"value\": \"result.total\",\n\t\t\t\t\t\t\t\t\t\"themeCss\": {\n\t\t\t\t\t\t\t\t\t\t\"inputControlClassName\": {\n\t\t\t\t\t\t\t\t\t\t\t\"padding-and-margin:default\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"marginBottom\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"marginTop\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"marginRight\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"marginLeft\": \"\"\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"id\": \"u:0f1bd8fc2f2b\",\n\t\t\t\t\t\t\t\"collapsed\": true,\n\t\t\t\t\t\t\t\"headingClassName\": \"\",\n\t\t\t\t\t\t\t\"bodyClassName\": \"p\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"fieldset\",\n\t\t\t\t\t\t\t\"title\": \"请求方法\",\n\t\t\t\t\t\t\t\"collapsable\": true,\n\t\t\t\t\t\t\t\"body\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"请求名称\",\n\t\t\t\t\t\t\t\t\t\"name\": \"fetchName\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:a3e712484fae\",\n\t\t\t\t\t\t\t\t\t\"value\": \"fetchTableList\",\n\t\t\t\t\t\t\t\t\t\"description\": \"追加了YAPI数据则不使用此参数\",\n\t\t\t\t\t\t\t\t\t\"themeCss\": {\n\t\t\t\t\t\t\t\t\t\t\"labelClassName\": {\n\t\t\t\t\t\t\t\t\t\t\t\"padding-and-margin:default\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"marginTop\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"marginRight\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"marginBottom\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"marginLeft\": \"\"\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"labelClassName\": \"labelClassName-a3e712484fae\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"接口数据字段 PATH\",\n\t\t\t\t\t\t\t\t\t\"name\": \"result\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:8c082acf7db2\",\n\t\t\t\t\t\t\t\t\t\"value\": \"[\\\"result\\\"][\\\"records\\\"]\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"service方法名\",\n\t\t\t\t\t\t\t\t\t\"name\": \"serviceName\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:cfbbdd07366b\",\n\t\t\t\t\t\t\t\t\t\"value\": \"getTableList\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"id\": \"u:382f8cdf59a6\",\n\t\t\t\t\t\t\t\"collapsed\": true,\n\t\t\t\t\t\t\t\"className\": \"\",\n\t\t\t\t\t\t\t\"headingClassName\": \"\",\n\t\t\t\t\t\t\t\"bodyClassName\": \"p-r p-l p-b\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"fieldset\",\n\t\t\t\t\t\t\t\"title\": \"新增/编辑弹框\",\n\t\t\t\t\t\t\t\"collapsable\": true,\n\t\t\t\t\t\t\t\"body\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"是否包含弹框\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"includeModifyModal\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:03957070af9e\",\n\t\t\t\t\t\t\t\t\t\"value\": false\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"combo\",\n\t\t\t\t\t\t\t\t\t\"label\": \"表单项\",\n\t\t\t\t\t\t\t\t\t\"name\": \"modifyModal.formItems\",\n\t\t\t\t\t\t\t\t\t\"multiple\": true,\n\t\t\t\t\t\t\t\t\t\"addable\": true,\n\t\t\t\t\t\t\t\t\t\"removable\": true,\n\t\t\t\t\t\t\t\t\t\"removableMode\": \"icon\",\n\t\t\t\t\t\t\t\t\t\"strictMode\": false,\n\t\t\t\t\t\t\t\t\t\"addBtn\": {\n\t\t\t\t\t\t\t\t\t\t\"label\": \"新增\",\n\t\t\t\t\t\t\t\t\t\t\"icon\": \"fa fa-plus\",\n\t\t\t\t\t\t\t\t\t\t\"level\": \"primary\",\n\t\t\t\t\t\t\t\t\t\t\"size\": \"sm\",\n\t\t\t\t\t\t\t\t\t\t\"id\": \"u:86cc27b6a663\"\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"items\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"key\",\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"u:62cc1cf36c73\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"字段名（key）\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"type\",\n\t\t\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"string\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"number\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"number\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"boolean\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"Dayjs\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"Dayjs\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"string[]\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"string[]\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"number[]\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"number[]\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"boolean[]\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"boolean[]\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"[Dayjs,Dayjs]\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"[Dayjs,Dayjs]\"\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"u:b165c75e5e1a\",\n\t\t\t\t\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"字段类型\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"字段可选\",\n\t\t\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"optional\",\n\t\t\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"u:68fc4c85fb03\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"字段名字后加?\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"defaultValue\",\n\t\t\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"\\\"\\\"\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"\\\"\\\"\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"false\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"false\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"true\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"true\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"0\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"undefined\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"undefined\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"[]\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"[]\"\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"u:379ea92fb3c6\",\n\t\t\t\t\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"默认值\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"component\",\n\t\t\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"input\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"input\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"input-password\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"input-password\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"input-number\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"input-number\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"textarea\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"textarea\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"select\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"select\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"radio-group\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"radio-group\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"checkbox-group\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"checkbox-group\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"switch\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"switch\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"date-picker\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"date-picker\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"time-ticker\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"time-picker\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"range-picker\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"range-picker\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"transfer\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"transfer\"\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"u:7932ea3b05da\",\n\t\t\t\t\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"组件\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"label\",\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"u:5bb237f20098\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"label\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"placeholder\",\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"u:580898257491\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"placeholder\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"required\",\n\t\t\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"required\",\n\t\t\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"u:559dbdbb01da\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"验证规则加required\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"message\",\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"u:55013279d659\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"校验失败 message\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"不能为空\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"更多组件配置\",\n\t\t\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"showMore\",\n\t\t\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"u:67e0cb5b7496\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"labelInValue\",\n\t\t\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"labelInValue\",\n\t\t\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"u:7fd6f1b233d9\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"是否把每个选项的 label 包装到 value 中\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'select'}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"mode\",\n\t\t\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"multiple\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"multiple\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"tags\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"tags\"\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"mode\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"设置 Select 的模式为多选或标签\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'select'}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"optionFilterProp\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"optionFilterProp\",\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"搜索时过滤对应的 option 属性\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"label\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'select'}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"showSearch\",\n\t\t\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"showSearch\",\n\t\t\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"使单选模式可搜索\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'select'}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"hideArrow\",\n\t\t\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"hideArrow\",\n\t\t\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"是否隐藏下拉小箭头\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'select'}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"maxlength\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"maxlength\",\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"最大长度\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'input' && modifyModal.formItems[index].component !== 'input-password' && modifyModal.formItems[index].component !== 'textarea')}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"showCount\",\n\t\t\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"showCount\",\n\t\t\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"是否展示字数\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'input' && modifyModal.formItems[index].component !== 'input-password' && modifyModal.formItems[index].component !== 'textarea')}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"max\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"max\",\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"最大值\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'input-number'}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"min\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"min\",\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"最小值\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'input-number'}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"step\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"step\",\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"每次改变步数，可以为小数\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'input-number'}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"checkedChildren\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"checkedChildren\",\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"选中时的内容\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'switch'}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"unCheckedChildren\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"unCheckedChildren\",\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"非选中时的内容\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'switch'}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"checkedValue\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"checkedValue\",\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"选中时的值\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'switch'}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"unCheckedValue\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"unCheckedValue\",\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"非选中时的值\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'switch'}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"picker\",\n\t\t\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"date\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"date\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"week\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"week\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"month\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"month\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"quarter\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"quarter\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"year\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"year\"\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"picker\",\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"设置选择器类型\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'date-picker' && modifyModal.formItems[index].component !== 'range-picker')}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"showTime\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"showTime\",\n\t\t\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"增加时间选择功能\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'date-picker' && modifyModal.formItems[index].component !== 'range-picker' || modifyModal.formItems[index].picker !== 'date')}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"showNow\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"showNow\",\n\t\t\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"当设定了 showTime 的时候，面板是否显示“此刻”按钮\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'date-picker' && modifyModal.formItems[index].component !== 'range-picker' || modifyModal.formItems[index].picker !== 'date')}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"showToday\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"showToday\",\n\t\t\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"是否展示“今天”按钮\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'date-picker' && modifyModal.formItems[index].component !== 'range-picker' || modifyModal.formItems[index].picker !== 'date')}\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"syncFields\": [],\n\t\t\t\t\t\t\t\t\t\"tabsMode\": true,\n\t\t\t\t\t\t\t\t\t\"draggable\": true,\n\t\t\t\t\t\t\t\t\t\"draggableTip\": \"可拖动排序\",\n\t\t\t\t\t\t\t\t\t\"tabsStyle\": \"line\",\n\t\t\t\t\t\t\t\t\t\"tabsLabelTpl\": \"表单项${index+1}\",\n\t\t\t\t\t\t\t\t\t\"multiLine\": true,\n\t\t\t\t\t\t\t\t\t\"noBorder\": false,\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!includeModifyModal}\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"bodyClassName\": \"p\",\n\t\t\t\t\t\t\t\"collapsed\": true\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\t\"submitText\": \"\"\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"pullRefresh\": {\n\t\t\t\t\"disabled\": true\n\t\t\t},\n\t\t\t\"regions\": [\n\t\t\t\t\"body\"\n\t\t\t],\n\t\t\t\"style\": {\n\t\t\t\t\"boxShadow\": \" 0px 0px 0px 0px transparent\"\n\t\t\t},\n\t\t\t\"asideResizor\": false\n\t\t}\n\t},\n\t\"conditionFiles\": {\n\t\t\"includeModifyModal\": {\n\t\t\t\"value\": false,\n\t\t\t\"exclude\": [\n\t\t\t\t\"/ModifyModal/index.vue.ejs\",\n\t\t\t\t\"/ModifyModal/model.ts.ejs\",\n\t\t\t\t\"/ModifyModal/presenter.tsx.ejs\",\n\t\t\t\t\"/ModifyModal/presenter.ts.ejs\",\n\t\t\t\t\"/ModifyModal/service.ts.ejs\"\n\t\t\t]\n\t\t}\n\t},\n\t\"excludeCompile\": [\n\t\t\"temp.mock.script.ejs\"\n\t]\n}"
  },
  {
    "path": "materials/blocks/antdv2 增删改查列表页/config/schema.ts",
    "content": "export type PageConfig = {\n  filters: {\n    component: string;\n    /**\n     * @description 翻译成英文，驼峰格式\n     * @type {string}\n     */\n    key: string;\n    /**\n     * @description 保持原始内容，不要翻译\n     * @type {string}\n     */\n    label: string;\n    /**\n     * @description 保持原始内容，不要翻译\n     * @type {string}\n     */\n    placeholder: string;\n  }[];\n  columns: {\n    slot: boolean;\n    /**\n     * @description 保持原始内容，不要翻译\n     * @type {string}\n     */\n    title: string;\n    /**\n     * @description 翻译成英文，驼峰格式\n     * @type {string}\n     */\n    dataIndex: string;\n    /**\n     * @description 翻译成英文，驼峰格式\n     * @type {string}\n     */\n    key: string;\n  }[];\n  pagination: {\n    show: boolean;\n    page: string;\n    size: string;\n    total: string;\n  };\n  includeModifyModal: boolean;\n  fetchName: string;\n  result: string;\n  serviceName: string;\n};\n"
  },
  {
    "path": "materials/blocks/antdv2 增删改查列表页/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/blocks/antdv2 增删改查列表页/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/blocks/antdv2 增删改查列表页/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: (lowcodeContext) => {\n    lowcodeContext.outputChannel.appendLine(__dirname);\n    lowcodeContext.outputChannel.appendLine(__filename);\n    lowcodeContext.outputChannel.appendLine(process.cwd());\n    lowcodeContext.outputChannel.appendLine(\n      JSON.stringify(lowcodeContext.model),\n    );\n    if (!lowcodeContext.model.includeModifyModal) {\n      // lowcodeContext.libs.fsExtra.removeSync(\n      //   path.join(\n      //     path.join(lowcodeContext.env.tempWorkPath, 'src', 'ModifyModal'),\n      //   ),\n      // );\n    }\n  },\n  complete: (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    try {\n      main.handleComplete();\n    } catch (ex) {}\n  },\n  initFiltersFromImage: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    const res = await main.handleInitFiltersFromImage();\n    return res;\n  },\n  initFiltersFromText: (lowcodeContext) => {\n    let filters = lowcodeContext.params\n      .replace(/\\r\\n/g, '\\n')\n      .replace(/\\r/g, '\\n')\n      .split('\\n');\n    filters = filters.map((item) => {\n      const s = item.replace(/：|：/g, ':').split(':');\n      return {\n        component: (s[1] || '').indexOf('选择') > -1 ? 'select' : 'input',\n        key: s[0].trim(),\n        label: s[0].trim(),\n        placeholder: s[1] || '',\n      };\n    });\n    return {\n      updateModelImmediately: false,\n      onlyUpdateParams: false,\n      params: '',\n      model: { ...lowcodeContext.model, filters },\n    };\n  },\n  initColumnsFromImage: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    const res = await main.handleInitColumnsFromImage();\n    return res;\n  },\n  initColumnsFromText: (lowcodeContext) => {\n    let columns = lowcodeContext.params\n      .replace(/\\r\\n/g, '\\n')\n      .replace(/\\r/g, '\\n')\n      .split('\\n');\n    columns = columns.map((s) => ({\n      slot: false,\n      title: s,\n      dataIndex: s,\n      key: s,\n    }));\n    return {\n      updateModelImmediately: false,\n      onlyUpdateParams: false,\n      params: '',\n      model: { ...lowcodeContext.model, columns },\n    };\n  },\n  askChatGPT: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    const res = await main.handleAskChatGPT();\n    return res;\n  },\n  OCR: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    const res = await main.handleOCR();\n    return res;\n  },\n};\n"
  },
  {
    "path": "materials/blocks/antdv2 增删改查列表页/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { CompileContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/blocks/antdv2 增删改查列表页/script/src/main.ts",
    "content": "import * as path from 'path';\nimport { window, workspace } from 'vscode';\nimport * as fs from 'fs-extra';\nimport * as execa from 'execa';\nimport * as ejs from 'ejs';\nimport axios from 'axios';\nimport { translate } from '@share/TypeChatSlim/index';\nimport { generalBasic } from '@share/BaiduOCR/index';\nimport { typescriptToMock } from '@share/utils/json';\nimport { context } from './context';\nimport { PageConfig } from '../../config/schema';\n\nexport async function handleOCR() {\n  const { lowcodeContext } = context;\n  if (!lowcodeContext?.clipboardImage) {\n    window.showInformationMessage('剪贴板里没有截图');\n    return {\n      updateModelImmediately: false,\n      onlyUpdateParams: true,\n      params: '',\n      model: lowcodeContext?.model,\n    };\n  }\n  const ocrRes = await generalBasic({ image: lowcodeContext!.clipboardImage! });\n  return {\n    updateModelImmediately: false,\n    onlyUpdateParams: true,\n    params: ocrRes.words_result.map((s) => s.words).join('\\r\\n'),\n    model: lowcodeContext?.model,\n  };\n}\n\nexport async function handleInitFiltersFromImage() {\n  const { lowcodeContext } = context;\n  if (!lowcodeContext?.clipboardImage) {\n    window.showInformationMessage('剪贴板里没有截图');\n    return lowcodeContext?.model;\n  }\n  const ocrRes = await generalBasic({ image: lowcodeContext!.clipboardImage! });\n  const filters = ocrRes.words_result.map((s) => s.words);\n  const formatedFilters = filters.map((item) => {\n    const s = item.replace(/：|：/g, ':').split(':');\n    return {\n      component: (s[1] || '').indexOf('选择') > -1 ? 'select' : 'input',\n      key: s[0].replace(/:|：/g, '').trim(),\n      label: s[0].replace(/:|：/g, '').trim(),\n      placeholder: s[1],\n    };\n  });\n  return {\n    updateModelImmediately: false,\n    onlyUpdateParams: false,\n    params: '',\n    model: { ...lowcodeContext.model, filters: formatedFilters },\n  };\n}\n\nexport async function handleInitColumnsFromImage() {\n  const { lowcodeContext } = context;\n  if (!lowcodeContext?.clipboardImage) {\n    window.showInformationMessage('剪贴板里没有截图');\n    return lowcodeContext?.model;\n  }\n  const ocrRes = await generalBasic({ image: lowcodeContext!.clipboardImage! });\n  const columns = ocrRes.words_result.map((s) => ({\n    slot: false,\n    title: s.words,\n    dataIndex: s.words,\n    key: s.words,\n  }));\n  return {\n    updateModelImmediately: false,\n    onlyUpdateParams: false,\n    params: '',\n    model: { ...lowcodeContext.model, columns },\n  };\n}\n\nexport async function handleAskChatGPT() {\n  const { lowcodeContext } = context;\n  const schema = fs.readFileSync(\n    path.join(lowcodeContext!.materialPath, 'config/schema.ts'),\n    'utf8',\n  );\n  const typeName = 'PageConfig';\n  const res = await translate<PageConfig>({\n    schema,\n    typeName,\n    request: JSON.stringify(lowcodeContext!.model as PageConfig),\n    completePrompt:\n      `你是一个根据以下 TypeScript 类型定义将用户请求转换为 \"${typeName}\" 类型的 JSON 对象的服务，并且按照字段的注释进行处理:\\n` +\n      `\\`\\`\\`\\n${schema}\\`\\`\\`\\n` +\n      `以下是用户请求:\\n` +\n      `\"\"\"\\n${JSON.stringify(lowcodeContext!.model as PageConfig)}\\n\"\"\"\\n` +\n      `The following is the user request translated into a JSON object with 2 spaces of indentation and no properties with the value undefined:\\n`,\n    createChatCompletion: lowcodeContext!.createChatCompletion,\n    showWebview: true,\n    extendValidate: (jsonObject) => ({ success: true, data: jsonObject }),\n  });\n  lowcodeContext!.outputChannel.appendLine(JSON.stringify(res, null, 2));\n  if (res.success) {\n    return {\n      updateModelImmediately: false,\n      onlyUpdateParams: false,\n      params: '',\n      model: { ...res.data },\n    };\n  }\n  return lowcodeContext!.model;\n}\n\nexport async function handleComplete() {\n  const { lowcodeContext } = context;\n  const createBlockPath = context.lowcodeContext?.createBlockPath;\n  if (createBlockPath) {\n    // #region 更新 mock 服务\n    const mockType = fs\n      .readFileSync(path.join(createBlockPath, 'temp.mock.type').toString())\n      .toString();\n    fs.removeSync(path.join(createBlockPath, 'temp.mock.type'));\n    const { mockCode, mockData } = typescriptToMock(mockType);\n    const mockTemplate = fs\n      .readFileSync(\n        path.join(createBlockPath, 'temp.mock.script.ejs').toString(),\n      )\n      .toString();\n    fs.removeSync(path.join(createBlockPath, 'temp.mock.script.ejs'));\n    // @ts-ignore\n    if (!lowcodeContext?.model.includeModifyModal) {\n      fs.removeSync(path.join(path.join(createBlockPath, 'ModifyModal')));\n    }\n    const mockScript = ejs.render(mockTemplate, {\n      ...lowcodeContext!.model,\n      mockCode,\n      mockData,\n      createBlockPath: createBlockPath.replace(':', ''),\n    });\n    const mockProjectPathRes = await axios\n      .get('http://localhost:3000/mockProjectPath', { timeout: 1000 })\n      .catch(() => {\n        // window.showInformationMessage(\n        //   '获取 mock 项目路径失败，跳过更新 mock 服务',\n        // );\n      });\n    if (mockProjectPathRes?.data.result) {\n      const projectName = workspace.rootPath\n        ?.replace(/\\\\/g, '/')\n        .split('/')\n        .pop();\n      const mockRouteFile = path.join(\n        mockProjectPathRes.data.result,\n        `${projectName}.js`,\n      );\n      let mockFileContent = `\n\t\t\timport KoaRouter from 'koa-router';\n\t\t\timport proxy from '../middleware/Proxy';\n\t\t\timport { delay } from '../lib/util';\n\n\t\t\tconst Mock = require('mockjs');\n\n\t\t\tconst { Random } = Mock;\n\n\t\t\tconst router = new KoaRouter();\n\t\t\trouter{{mockScript}}\n\t\t\tmodule.exports = router;\n\t\t\t`;\n\n      if (fs.existsSync(mockRouteFile)) {\n        mockFileContent = fs.readFileSync(mockRouteFile).toString().toString();\n        const index = mockFileContent.lastIndexOf(')') + 1;\n        mockFileContent = `${mockFileContent.substring(\n          0,\n          index,\n        )}{{mockScript}}\\n${mockFileContent.substring(index)}`;\n      }\n      mockFileContent = mockFileContent.replace(/{{mockScript}}/g, mockScript);\n      fs.writeFileSync(mockRouteFile, mockFileContent);\n      try {\n        execa.sync('node', [\n          path.join(\n            mockProjectPathRes.data.result\n              .replace(/\\\\/g, '/')\n              .replace('/src/routes', ''),\n            '/node_modules/eslint/bin/eslint.js',\n          ),\n          mockRouteFile,\n          '--resolve-plugins-relative-to',\n          mockProjectPathRes.data.result\n            .replace(/\\\\/g, '/')\n            .replace('/src/routes', ''),\n          '--fix',\n        ]);\n      } catch (err) {\n        console.log(err);\n      }\n      // #endregion\n    }\n  }\n}\n"
  },
  {
    "path": "materials/blocks/antdv2 增删改查列表页/src/ModifyModal/index.vue.ejs",
    "content": "<template>\n  <a-modal\n    :visible=\"props.visible\"\n    :title=\"props.title\"\n    :width=\"700\"\n    @ok=\"presenter.handleSubmit\"\n    @cancel=\"presenter.handleCancel\"\n    :ok-button-props=\"{ loading: model.loading.value }\"\n    :mask-closable=\"false\"\n  >\n    <a-form :label-col=\"{ span: 4 }\" :wrapper-col=\"{ span: 12 }\">\n\t\t\t<% modifyModal.formItems.map(item => { _%>\n\t\t\t\t<% if(item.component === \"input\") { _%>\n\t\t\t\t\t<a-form-item\n\t\t\t\t\t\t<% if(item.label) { _%>\n\t\t\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\tv-bind=\"presenter.validateInfos.<%= item.key %>\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<a-input \n\t\t\t\t\t\t\tv-model:value=\"model.formData.<%= item.key %>\" \n\t\t\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\t\t\tallow-clear\n\t\t\t\t\t\t\t<% if(item.maxlength) { _%>\n\t\t\t\t\t\t\t:maxlength=\"<%= item.maxlength %>\"\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t\t<% if(item.showCount) { _%>\n\t\t\t\t\t\t\tshowCount\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t>\n\t\t\t\t\t\t</a-input>\n\t\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item.component === \"input-password\") { _%>\n\t\t\t\t\t<a-form-item\n\t\t\t\t\t\t<% if(item.label) { _%>\n\t\t\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\tv-bind=\"presenter.validateInfos.<%= item.key %>\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<a-input-password\n\t\t\t\t\t\t\tv-model:value=\"model.formData.<%= item.key %>\" \n\t\t\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\t\t\tallowClear\n\t\t\t\t\t\t\t<% if(item.maxlength) { _%>\n\t\t\t\t\t\t\t:maxlength=\"<%= item.maxlength %>\"\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t\t<% if(item.showCount) { _%>\n\t\t\t\t\t\t\tshowCount\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t></a-input-password>\n\t\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item.component === \"input-number\") { _%>\n\t\t\t\t\t<a-form-item\n\t\t\t\t\t\t<% if(item.label) { _%>\n\t\t\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\tv-bind=\"presenter.validateInfos.<%= item.key %>\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<a-input-number\n\t\t\t\t\t\t\tv-model:value=\"model.formData.<%= item.key %>\"\n\t\t\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\t\t\tallowClear\n\t\t\t\t\t\t\t<% if(item.max) { _%>\n\t\t\t\t\t\t\t:max=\"<%= item.max %>\"\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t\t<% if(item.min) { _%>\n\t\t\t\t\t\t\t:min=\"<%= item.min %>\"\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t\t<% if(item.step) { _%>\n\t\t\t\t\t\t\t:step=\"<%= item.step %>\"\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t></a-input-number>\n\t\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item.component === \"textarea\") { _%>\n\t\t\t\t\t<a-form-item\n\t\t\t\t\t\t<% if(item.label) { _%>\n\t\t\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\tv-bind=\"presenter.validateInfos.<%= item.key %>\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<a-textarea\n\t\t\t\t\t\t\tv-model:value=\"model.formData.<%= item.key %>\" \n\t\t\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\t\t\tallow-clear\n\t\t\t\t\t\t\t<% if(item.maxlength) { _%>\n\t\t\t\t\t\t\t:maxlength=\"<%= item.maxlength %>\"\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t\t<% if(item.showCount) { _%>\n\t\t\t\t\t\t\tshowCount\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t>\n\t\t\t\t\t\t</a-textarea>\n\t\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item.component === \"select\") { _%>\n\t\t\t\t\t<a-form-item \n\t\t\t\t\t\t<% if(item.label) { _%>\n\t\t\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t\t\t<% } _%> \n\t\t\t\t\t\tv-bind=\"presenter.validateInfos.<%= item.key %>\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<a-select\n\t\t\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\t\t\tallow-clear\n\t\t\t\t\t\t\t:options=\"model.options.<%= item.key %>\"\n\t\t\t\t\t\t\tv-model:value=\"model.formData.<%= item.key %>\"\n\t\t\t\t\t\t\t<% if(item.labelInValue) { _%>\n\t\t\t\t\t\t\tlabelInValue\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t\t<% if(item.mode) { _%>\n\t\t\t\t\t\t\tmode=\"<%= item.mode %>\"\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t\toptionFilterProp=\"<%= item.optionFilterProp || 'label' %>\"\n\t\t\t\t\t\t\t<% if(item.showSearch) { _%>\n\t\t\t\t\t\t\tshowSearch\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t\t<% if(item.hideArrow) { _%>\n\t\t\t\t\t\t\t:showArrow=\"false\"\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t></a-select>\n\t\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item.component === \"radio-group\") { _%>\n\t\t\t\t\t<a-form-item \n\t\t\t\t\t\t<% if(item.label) { _%>\n\t\t\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\tv-bind=\"presenter.validateInfos.<%= item.key %>\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<a-radio-group v-model:value=\"model.formData.<%= item.key %>\">\n\t\t\t\t\t\t\t<a-radio\n\t\t\t\t\t\t\t\tv-for=\"item in model.options.<%= item.key %>\"\n\t\t\t\t\t\t\t\t:value=\"item.value\"\n\t\t\t\t\t\t\t\t:key=\"item.value\"\n\t\t\t\t\t\t\t\t>{{ item.label }}\n\t\t\t\t\t\t\t</a-radio>\n\t\t\t\t\t\t</a-radio-group>\n\t\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item.component === \"checkbox-group\") { _%>\n\t\t\t\t\t<a-form-item \n\t\t\t\t\t\t<% if(item.label) { _%>\n\t\t\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\tv-bind=\"presenter.validateInfos.<%= item.key %>\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<a-checkbox-group\n\t\t\t\t\t\t\tv-model:value=\"model.formData.<%= item.key %>\"\n\t\t\t\t\t\t\tstyle=\"width: 100%; margin-top: 6px\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<a-row>\n\t\t\t\t\t\t\t<a-col\n\t\t\t\t\t\t\t\t:span=\"8\"\n\t\t\t\t\t\t\t\tv-for=\"item in model.options.<%= item.key %>\"\n\t\t\t\t\t\t\t\t:key=\"item.value\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<a-checkbox :value=\"item.value\">{{ item.label }} </a-checkbox>\n\t\t\t\t\t\t\t</a-col>\n\t\t\t\t\t\t\t</a-row>\n\t\t\t\t\t\t</a-checkbox-group>\n\t\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item.component === \"switch\") { _%>\n\t\t\t\t\t<a-form-item \n\t\t\t\t\t\t<% if(item.label) { _%>\n\t\t\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t\t\t<% } _%> \n\t\t\t\t\t\tv-bind=\"presenter.validateInfos.<%= item.key %>\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<a-switch\n\t\t\t\t\t\t\tv-model:checked=\"model.formData.<%= item.key %>\"\n\t\t\t\t\t\t\t<% if(item.checkedChildren) { _%>\n\t\t\t\t\t\t\tcheckedChildren=\"<%= item.checkedChildren %>\"\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t\t<% if(item.unCheckedChildren) { _%>\n\t\t\t\t\t\t\tunCheckedChildren=\"<%= item.unCheckedChildren %>\"\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t\t<% if(item.checkedValue) { _%>\n\t\t\t\t\t\t\t\tcheckedValue=\"<%= item.checkedValue || 'true' %>\"\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t\t<% if(item.unCheckedValue) { _%>\n\t\t\t\t\t\t\t\tunCheckedValue=\"<%= item.unCheckedValue || 'false' %>\"\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t></a-switch>\n\t\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item.component === \"date-picker\") { _%>\n\t\t\t\t\t<a-form-item \n\t\t\t\t\t\t<% if(item.label) { _%>\n\t\t\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t\t\t<% } _%> \n\t\t\t\t\t\tv-bind=\"presenter.validateInfos.<%= item.key %>\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<a-date-picker\n\t\t\t\t\t\t\tv-model:value=\"model.formData.<%= item.key %>\"\n\t\t\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\t\t\tallow-clear\n\t\t\t\t\t\t\tpicker=\"<%= item.picker || 'date' %>\"\n\t\t\t\t\t\t\t:showTime=\"<%= item.showTime || false %>\"\n\t\t\t\t\t\t\t:showNow=\"<%= item.showNow || false %>\"\n\t\t\t\t\t\t\t:showToday=\"<%= item.showToday || false %>\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item.component === \"range-picker\") { _%>\n\t\t\t\t\t<a-form-item \n\t\t\t\t\t\t<% if(item.label) { _%>\n\t\t\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t\t\t<% } _%> \n\t\t\t\t\t\tv-bind=\"presenter.validateInfos.<%= item.key %>\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<a-range-picker\n\t\t\t\t\t\t\tv-model:value=\"model.formData.<%= item.key %>\"\n\t\t\t\t\t\t\t:placeholder=\"[<%- item.placeholder || '\\'\\'' %>,<%- item.placeholder || '\\'\\'' %>]\"\n\t\t\t\t\t\t\tallow-clear\n\t\t\t\t\t\t\tpicker=\"<%= item.picker || 'date' %>\"\n\t\t\t\t\t\t\t:showTime=\"<%= item.showTime || false %>\"\n\t\t\t\t\t\t\t:showNow=\"<%= item.showNow || false %>\"\n\t\t\t\t\t\t\t:showToday=\"<%= item.showToday || false %>\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item.component === \"time-picker\") { _%>\n\t\t\t\t\t<a-form-item \n\t\t\t\t\t\t<% if(item.label) { _%>\n\t\t\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t\t\t<% } _%> \n\t\t\t\t\t\tv-bind=\"presenter.validateInfos.<%= item.key %>\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<a-time-picker\n\t\t\t\t\t\t\tv-model:value=\"model.formData.<%= item.key %>\"\n\t\t\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\t\t\tallow-clear\n\t\t\t\t\t\t/>\n\t\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%>\n\t\t\t<% }) _%>\n    </a-form>\n  </a-modal>\n</template>\n<script lang=\"ts\" setup>\nimport { usePresenter } from \"./presenter\";\n\ninterface IProps {\n  title: string\n  visible: boolean\n  action: 'add' | 'edit' | 'view'\n  id?: number\n}\n\ninterface IEmit {\n  (event: 'cancel'): void\n  (event: 'ok'): void\n}\n\nconst props = defineProps<IProps>()\n\nconst emit = defineEmits<IEmit>()\n\nconst presenter = usePresenter(props, emit);\nconst { model } = presenter;\n</script>\n"
  },
  {
    "path": "materials/blocks/antdv2 增删改查列表页/src/ModifyModal/model.ts.ejs",
    "content": "import { reactive, ref } from \"vue\";\n<% if(modifyModal.formItems.some(s => (s.type || \"\").indexOf(\"Dayjs\") > -1)) { _%>\nimport type { Dayjs } from \"dayjs\";\n<% } _%>\n\nexport interface IFormData {\n\tid?:number;\n\t<% modifyModal.formItems.map(item => { _%>\n\t\t<%= item.key %><% if(item.optional){ _%>?<% } _%>: <%= item.type %>;\n\t<% }) _%>\n}\n\nconst defaultFormData: IFormData = {\n\t<% modifyModal.formItems.map(item => { _%>\n\t\t<%= item.key %>: <%- item.defaultValue || '\\\"\\\"' %>,\n\t<% }) _%>\n};\n<% if(modifyModal.formItems.some(s => s.component === \"select\" || s.component === \"radio-group\" || s.component === \"checkbox-group\")){ %>\ninterface IOptionItem {\n  label: string;\n  value: string;\n}\n\ninterface IOptions {\n  <% modifyModal.formItems.filter(s => s.component === \"select\" || s.component === \"radio-group\" || s.component === \"checkbox-group\").map(item => { _%>\n\t\t<%= item.key %>: IOptionItem[];\n\t<% }) _%>\n}\n\nconst defaultOptions: IOptions = {\n  <% modifyModal.formItems.filter(s => s.component === \"select\" || s.component === \"radio-group\" || s.component === \"checkbox-group\").map(item => { _%>\n\t\t<%= item.key %>: [],\n\t<% }) _%>\n};\n<% } %>\n\nexport const useModel = () => {\n  const formData = reactive<IFormData>({ ...defaultFormData });\n\t<% if(modifyModal.formItems.some(s => s.component === \"select\" || s.component === \"radio-group\" || s.component === \"checkbox-group\")){ _%>\n  const options = reactive<IOptions>({ ...defaultOptions });\n\t<% } _%>\n  const loading = ref(false);\n\n  return { \n\t\tformData, \n\t\t<% if(modifyModal.formItems.some(s => s.component === \"select\" || s.component === \"radio-group\" || s.component === \"checkbox-group\")){ _%>\n\t\toptions,\n\t\t<% } _%>\n\t\tloading \n\t};\n};\n\nexport type Model = ReturnType<typeof useModel>;\n"
  },
  {
    "path": "materials/blocks/antdv2 增删改查列表页/src/ModifyModal/presenter.ts.ejs",
    "content": "import Service from \"./service\";\nimport { useModel } from \"./model\";\nimport { Form, message } from \"ant-design-vue\";\nimport { watch, reactive } from \"vue\";\nimport { Rule } from 'ant-design-vue/es/form/interface'\n\ninterface IProps {\n  title: string\n  visible: boolean\n  action: 'add' | 'edit' | 'view'\n  id?: number\n}\n\ninterface IEmit {\n  (event: 'cancel'): void\n  (event: 'ok'): void\n}\n\nconst { useForm } = Form;\n\nexport const usePresenter = (props: IProps, emit: IEmit) => {\n  const model = useModel();\n  const service = new Service(model);\n\n  const rules: Record<string, Rule[]> = reactive({\n\t\t<% modifyModal.formItems.map(item => { _%>\n\t\t\t<%= item.key %>: [{ required: <%= item.required || false %>, message: \"<%= item.message %>\" }],\n\t\t<% }) _%>\n  });\n\n  const { resetFields, validate, validateInfos } = useForm(\n    model.formData,\n    rules,\n  );\n\n  watch(\n    () => props.visible,\n    () => {\n      if (props.visible && props.id) {\n        service.getDetail(props.id as number);\n      }\n    },\n  );\n\n  const handleSubmit = () => {\n    validate().then(() => {\n      if (props.action === \"add\") {\n        service.create().then(() => {\n          message.success(\"新建成功\");\n          resetFields();\n          emit(\"ok\");\n        });\n      } else {\n        service.edit().then(() => {\n          message.success(\"提交成功\");\n          resetFields();\n          emit(\"ok\");\n        });\n      }\n    });\n  };\n\n  const handleCancel = () => {\n    resetFields();\n    emit(\"cancel\");\n  };\n\n  return {\n    model,\n    service,\n    handleSubmit,\n    handleCancel,\n    validateInfos,\n  };\n};\n"
  },
  {
    "path": "materials/blocks/antdv2 增删改查列表页/src/ModifyModal/service.ts.ejs",
    "content": "import { Model } from \"./model\";\n\nexport default class Service {\n  private model: Model;\n\n  constructor(model: Model) {\n    this.model = model;\n  }\n\n  async getDetail(id: number) {\n    // const res = await fetchDetail({ id });\n    // this.model.formData.id = id;\n\t<% modifyModal.formItems.map(item => { _%>\n\t\t// this.model.formData.<%= item.key %> = res.result<%= item.key %>;\n\t<% }) _%>\n  }\n\n  async create() {\n    // this.model.loading.value = true;\n    // await create({\n\t<% modifyModal.formItems.map(item => { _%>\n\t\t// <%= item.key %>: this.model.formData.<%= item.key %>,\n\t<% }) _%>\n    // }).finally(() => {\n    //   this.model.loading.value = false;\n    // });\n  }\n\n  async edit() {\n    // this.model.loading.value = true;\n    // await edit(\n    //   { id: this.model.formData.id! },\n    //   {\n\t<% modifyModal.formItems.map(item => { _%>\n\t\t// <%= item.key %>: this.model.formData.<%= item.key %>,\n\t<% }) _%>\n    //   },\n    // ).finally(() => {\n    //   this.model.loading.value = false;\n    // });\n  }\n}\n"
  },
  {
    "path": "materials/blocks/antdv2 增删改查列表页/src/api.ts.ejs",
    "content": "import request from \"@/utils/request\";\n<% if (locals.api) { %>\n// #region <%= api.title %>\n<%= type %>\n\n<% if (api.req_query.length > 0 || api.req_params.length > 0 || api.query_path.params.length > 0) { _%>\nexport interface I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Params {\n\t<% api.req_query.filter(query => query.name !== pagination.page && query.name !== pagination.size).map(query => { _%>\n\t\t<%= query.name %>?: string;\n\t<% }) _%>\n\t<% api.req_params.filter(s => s.name !== pagination.page && s.name !== pagination.size).map(query => { _%>\n\t\t<%= query.name %>?: string;\n\t<% }) _%>\n\t<% api.query_path.params.filter(s => s.name !== pagination.page && s.name !== pagination.size).map(query => { _%>\n\t\t<%= query.name %>?: string;\n\t<% }) _%>\n\t<% if (pagination.show) { _%>\n\t\t<%= pagination.page %>: number;\n\t\t<%= pagination.size %>: number;\n\t<% } _%>\n}\n<% } %> \n<% if (requestBodyType && api.req_body_other.indexOf('{}') < 0) { %>\n    <%= requestBodyType %> \n<% } %> \n\n/**\n* <%= api.title %> \n* /project/<%= api.project_id %>/interface/api/<%= api._id %> \n* @author <%= api.username %>  \n* \n<% if (api.req_query.length > 0 || api.req_params.length > 0 || api.query_path.params.length > 0) { -%>* @param {I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Params} params<%- \"\\n\" %><% } _%>\n<% if (requestBodyType && api.req_body_other.indexOf('{}')<0) { -%>* @param {I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Data} data<%- \"\\n\" %><% } _%>\n* @returns\n*/\nexport function <%= funcName %> (\n<% if (api.req_query.length>0 || api.req_params.length > 0 || api.query_path.params.length > 0) { %>\nparams: I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Params,\n<% } _%>\n<% if (requestBodyType) { %> \ndata: I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Data\n<% } %> \n) {\nreturn request<<%= typeName %>[\"result\"]>({\n\t  url: `http://127.0.0.1:3000<%= api.query_path.path.replace(/\\{/g,\"${params.\") %>`, \n\t\tmethod: '<%= api.method %>',\n\t\t<% if(api.req_query.length>0 || api.req_params.length > 0) { %>params,<% } _%>\n        <% if (requestBodyType && api.req_body_other.indexOf('{}')<0) {%>data,<% } %> \n\t})\n}\n// #endregion\n<% } else { %>\n// #region\nexport interface I<%= fetchName.slice(0, 1).toUpperCase() + fetchName.slice(1) %>Result {\n  code: number;\n\tmsg: string;\n\t<% if (!pagination.show) { _%>\n\tresult: {\n\t\t<% columns.map((item, index) => { _%>\n\t\t\t<%= item.key || `column${index+1}` %>: string;\n\t\t<% }) _%>\n\t\t}[];\n\t<% } else { _%>\n\t\tresult: {\n\t\t\trecords: {\n\t\t\t\t<% columns.map((item, index) => { _%>\n\t\t\t\t\t<%= item.key || `column${index+1}` %>: string;\n\t\t\t\t<% }) _%>\n\t\t\t}[];\n\t\t\ttotal: number;\n\t\t}\n\t<% } _%>\n}\n\nexport interface I<%= fetchName.slice(0, 1).toUpperCase() + fetchName.slice(1) %>Params {\n\t<% filters.map(item => { _%>\n\t\t<% if(item.component !== \"range-picker\") { _%>\n\t\t\t <%= item.key %>?: string;\n\t\t<% } else { _%>\n\t\t\t<%= item.key %>Start?: string;\n\t\t\t<%= item.key %>End?: string;\n\t\t<% } _%>\n\t<% }) _%>\n\t<% if (pagination.show) { _%>\n\t\t<%= pagination.page %>: number;\n\t\t<%= pagination.size %>: number;\n\t<% } _%>\n}\n\nexport function <%= fetchName %>(\nparams: I<%= fetchName.slice(0, 1).toUpperCase() + fetchName.slice(1) %>Params\n) {\nreturn request<I<%= fetchName.slice(0, 1).toUpperCase() + fetchName.slice(1) %>Result[\"result\"]>({\n\turl: `http://127.0.0.1:3000/<%= createBlockPath %>/<%= fetchName %>`, \n\tmethod: 'GET',\n\tparams,\n});\n}\n// #endregion\n<% } %>"
  },
  {
    "path": "materials/blocks/antdv2 增删改查列表页/src/index.vue.ejs",
    "content": "<template>\n  <a-row class=\"filterForm\" :gutter=\"30\">\n    <% filters.map(item => { _%> \n\t\t  <a-col :xs=\"24\" :sm=\"24\" :md=\"12\" :lg=\"12\" :xl=\"8\" :xxl=\"6\">\n\t\t\t\t<% if(item.component === \"select\") { %>\n\t\t\t\t<a-form-item label=\"<%= item.label %>\">\n\t\t\t\t\t<a-select\n\t\t\t\t\t\tv-model:value=\"model.filterForm.<%= item.key %>\"\n\t\t\t\t\t\t:options=\"model.options.<%= item.key %>\"\n\t\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\t\tshow-search\n\t\t\t\t\t\tallow-clear\n\t\t\t\t\t\t<% if(item.remoteFetch) { _%>\n\t\t\t\t\t\t:filter-option=\"false\"\n\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\toption-filter-prop=\"label\"\n\t\t\t\t\t\t@change=\"presenter.handleSearch\"\n\t\t\t\t\t\t<% if(item.remoteFetch) { _%>\n\t\t\t\t\t\t@search=\"presenter.handleSearch<%= item.key.slice(0, 1).toUpperCase() + item.key.slice(1) %>\"\n\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t></a-select>\n\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%> \n\t\t\t\t<% if(item.component === \"input\") { _%>\n\t\t\t\t<a-form-item label=\"<%= item.label %>\">\n\t\t\t\t\t<a-input\n\t\t\t\t\t\tv-model:value=\"model.filterForm.<%= item.key %>\"\n\t\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\t\tallow-clear\n\t\t\t\t\t\t@press-enter=\"presenter.handleSearch\"\n\t\t\t\t\t></a-input>\n\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%> \n\t\t\t\t<% if(item.component === \"range-picker\") { _%>\n\t\t\t\t<a-form-item label=\"<%= item.label %>\">\n\t\t\t\t\t<a-range-picker\n\t\t\t\t\t\tv-model:value=\"model.filterForm.<%= item.key %>\"\n\t\t\t\t\t\t:placeholder=\"['开始时间', '结束时间']\"\n\t\t\t\t\t\tformat=\"YYYY-MM-DD\"\n\t\t\t\t\t\tvalueFormat=\"YYYY-MM-DD\"\n\t\t\t\t\t\t@change=\"presenter.handleSearch\"\n\t\t\t\t\t/>\n\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%> \n\t\t\t</a-col>\n\t\t<% }) _%>\n\t\t<a-col style=\"text-align: right; flex: 1\">\n\t\t\t<a-space>\n\t\t\t\t<a-button @click=\"presenter.handleClear\">重置</a-button>\n        <a-button @click=\"presenter.handleSearch\" type=\"primary\">查询</a-button>\n        <a-button @click=\"presenter.handleCreate\" type=\"primary\">\n          <template #icon><PlusOutlined /></template>\n          新增\n        </a-button>\n\t\t\t</a-space>\n\t\t</a-col>\n  </a-row>\n  <a-table\n    :loading=\"model.loading.list\"\n    :columns=\"columns\"\n    :data-source=\"model.tableList.value\"\n    :pagination=\"false\"\n  >\n\t<% columns.filter(item => item.slot).map((item, index) => { _%>\n\t\t<template #<%= item.key %>=\"{ record }\">\n\t\t\t{{ record.<%= item.key %> }}\n\t\t</template>\n\t\t<% }) _%>\n\t\t<template #operation=\"{ record }\">\n\t\t\t<a-space :size=\"0\">\n\t\t\t\t<% if(includeModifyModal) { _%>\n\t\t\t\t<a-button\n\t\t\t\t\ttype=\"link\"\n\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t@click=\"\n\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\tpresenter.handleView(record);\n\t\t\t\t\t\t}\n\t\t\t\t\t\"\n\t\t\t\t>\n\t\t\t\t\t查看\n\t\t\t\t</a-button>\n\t\t\t\t<% } _%>\n\t\t\t\t<a-button\n\t\t\t\t\ttype=\"link\"\n\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t@click=\"\n\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\tpresenter.handleEdit(record);\n\t\t\t\t\t\t}\n\t\t\t\t\t\"\n\t\t\t\t>\n\t\t\t\t\t编辑\n\t\t\t\t</a-button>\n\t\t\t\t<a-button\n\t\t\t\t\ttype=\"link\"\n\t\t\t\t\tdanger\n\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t@click=\"\n\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\tpresenter.handleDel(record);\n\t\t\t\t\t\t}\n\t\t\t\t\t\"\n\t\t\t\t>\n\t\t\t\t\t删除\n\t\t\t\t</a-button>\n\t\t\t</a-space>\n\t\t</template>\n  </a-table>\n  <% if(pagination.show) { _%>\n  <a-pagination\n    style=\"margin-top: 10px\"\n    @change=\"presenter.handlePageChange\"\n\t\t@showSizeChange=\"presenter.handlePageChange\"\n    v-model:current=\"model.pagination.page\"\n    :total=\"model.pagination.total\"\n    show-size-changer\n    show-quick-jumper\n\t:show-total=\"(total: number) => `共 ${total} 条`\"\n  ></a-pagination>\n  <% } _%> <% if(includeModifyModal) { _%>\n  <ModifyModal\n    :id=\"model.modalInfo.id\"\n    :title=\"model.modalInfo.title\"\n    :visible=\"model.modalInfo.visible\"\n    :action=\"model.modalInfo.action\"\n    @ok=\"presenter.handleModalOk\"\n    @cancel=\"presenter.handleModalCancel\"\n  ></ModifyModal>\n  <% } _%>\n</template>\n<script lang=\"ts\" setup>\n  import { PlusOutlined } from \"@ant-design/icons-vue\";\n  <% if(includeModifyModal) { _%>\n  import ModifyModal from \"./ModifyModal/index.vue\";\n  <% } _%>\n  import { usePresenter } from \"./presenter\";\n\n  const presenter = usePresenter();\n  const { model } = presenter;\n\n  const columns = [\n    <% columns.map((item, index) => { _%>\n  \t\t{\n        title: \"<%= item.title || `column${index+1}` %>\",\n  \t\t\tdataIndex: \"<%= item.dataIndex || `column${index+1}` %>\",\n  \t\t\tkey: \"<%= item.key || `column${index+1}` %>\",\n  \t\t\t<% if(item.width) {%>width: \"<%= item.width %>\",<% } _%>\n\t\t\t\t<% if(item.slot) {%>slots: { customRender: \"<%= item.key %>\"},<% } _%>\n  \t\t},\n  \t<% }) _%>\n  \t{\n      title: \"操作\",\n      key: \"operation\",\n  \t\twidth: 100,\n\t\t\tslots:{customRender: \"operation\"}\n    }\n  ];\n</script>\n"
  },
  {
    "path": "materials/blocks/antdv2 增删改查列表页/src/model.ts.ejs",
    "content": "import { reactive, ref } from \"vue\";\n<% if(locals.api){ %>\nimport { I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Result } from \"./api\";\n<% } else { %>\nimport { I<%= fetchName.slice(0, 1).toUpperCase() + fetchName.slice(1) %>Result } from \"./api\";\n<% } %>\n<% if(!locals.api){ %>\ninterface ITableListItem {\n\t<% columns.map((item, index) => { _%>\n\t\t/** <%= item.title %> */\n\t\t<%= item.key || `column${index+1}` %>: string;\n\t<% }) _%>\n\t/**\n   * 接口返回的数据，新增字段不需要改 ITableListItem 直接从这里取\n   */\n\tapiResult: I<%= fetchName.slice(0, 1).toUpperCase() + fetchName.slice(1) %>Result<%- result %>[0]\n}\n<% } %>\ninterface IFormData {\n\t<% filters.map(item => { _%>\n\t\t/** <%= item.label %> */\n\t\t<% if(item.component === \"range-picker\") { _%>\n\t\t\t<%= item.key %>?: [string,string];\n\t\t<% } _%>\n\t\t<% if(item.component !== \"range-picker\") { _%>\n\t\t\t<%= item.key %>?: string;\n\t\t<% } _%>\n\t<% }) _%>\n}\n<% if(filters.some(s => s.component === \"select\" )){ %>\ninterface IOptionItem {\n  label: string;\n  value: string;\n}\n\ninterface IOptions {\n  <% filters.filter(s => s.component === \"select\").map(item => { _%>\n\t<%= item.key %>: IOptionItem[],\n  <% }) _%>\n}\n\nconst defaultOptions: IOptions = {\n\t<% filters.filter(s => s.component === \"select\").map(item => { _%>\n\t\t<%= item.key %>: [],\n\t<% }) _%>\n};\n<% } %>\nexport const defaultFormData: IFormData = {\n\t<% filters.map(item => { _%>\n\t\t<%= item.key %>: undefined,\n\t<% }) _%>\n};\n\nexport const useModel = () => {\n  const filterForm = reactive<IFormData>({ ...defaultFormData });\n\t<% if(filters.some(s => s.component === \"select\" )){ %>\n  \t\tconst options = reactive<IOptions>({ ...defaultOptions });\n\t<% } %>\n\t<% if(locals.api){ _%>\n\t\tconst tableList = ref<(I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Result<%- result %>[0] & { _?: unknown })[]>(\n\t\t\t[],\n\t\t);\n\t<% } else { _%>\n\t\tconst tableList = ref<(ITableListItem & { _?: unknown })[]>(\n\t\t\t[],\n\t\t);\n\t<% } _%>\n\t<% if(pagination.show) { %>\n\t\tconst pagination = reactive<{\n\t\t\tpage: number;\n\t\t\tpageSize: number;\n\t\t\ttotal: number;\n\t\t}>({\n\t\t\tpage: 1,\n\t\t\tpageSize: 10,\n\t\t\ttotal: 0,\n\t\t});\n\t<% } %>\n  const loading = reactive<{ list: boolean }>({\n    list: false,\n  });\n  <% if(includeModifyModal) { %>\n\tconst modalInfo = reactive<{\n\t\tvisible: boolean;\n\t\ttitle: string;\n\t\tid?: number;\n\t\taction: \"add\" | \"edit\" | \"view\";\n\t}>({\n\t\tvisible: false,\n\t\ttitle: \"\",\n\t\taction: \"add\",\n\t});\n  <% } %>\n  return {\n    filterForm,\n\t\t<% if(filters.some(s => s.component === \"select\" )){ _%>\n    options,\n\t\t<% } _%>\n    tableList,\n\t\t<% if(pagination.show) { _%>\n\t\tpagination,\n\t\t<% } _%>\n\t\t\tloading,\n\t\t<% if(includeModifyModal) { _%>\n\t\tmodalInfo,\n\t\t<% } _%>\n  };\n};\n\nexport type Model = ReturnType<typeof useModel>;\n"
  },
  {
    "path": "materials/blocks/antdv2 增删改查列表页/src/presenter.ts.ejs",
    "content": "import Service from \"./service\";\nimport { defaultFormData, useModel } from \"./model\";\nimport { createVNode, onMounted } from \"vue\";\nimport { message, Modal } from \"ant-design-vue\";\nimport { ExclamationCircleOutlined } from \"@ant-design/icons-vue\";\n<% if(filters.some(item => item.component === \"select\" && item.remoteFetch)) { _%>\nimport { useDebounceFn } from \"@vueuse/core\";\n<% } _%>\n\nexport const usePresenter = () => {\n  const model = useModel();\n  const service = new Service(model);\n\n  onMounted(() => {\n    service.<%= serviceName %>();\n  });\n\n  const handleClear = () => {\n\t\tObject.assign(model.filterForm, defaultFormData)\n\t\t<% if(pagination.show) { _%>\n\t\t\tmodel.pagination.page = 1;\n\t\t<% } _%>\n    service.<%= serviceName %>();\n  };\n\n  const handleSearch = () => {\n\t\t<% if(pagination.show) { _%>\n\t\t\tmodel.pagination.page = 1;\n\t\t<% } _%>\n    service.<%= serviceName %>();\n  };\n\n  <% if(pagination.show) { _%>\n  const handlePageChange = (page: number, pageSize: number) => {\n    if (pageSize !== model.pagination.pageSize) {\n      model.pagination.pageSize = pageSize;\n      model.pagination.page = 1;\n    } else {\n      model.pagination.page = page;\n    }\n    service.<%= serviceName %>();\n  };\n  <% } _%>\n\n\t<% filters.filter(item => item.component === \"select\" && item.remoteFetch).map(item => { _%> \n\tconst handleSearch<%= item.key.slice(0, 1).toUpperCase() + item.key.slice(1) %> = useDebounceFn((value: string) => {\n\t\tif (!value) {\n\t\t\treturn;\n\t\t}\n\t\tservice.search<%= item.key.slice(0, 1).toUpperCase() + item.key.slice(1) %>(value);\n\t}, 400);\n\t\n\t<% }) _%>\n\n  const handleDel = (record: typeof model.tableList.value[0]) => {\n    Modal.confirm({\n      title: \"此操作将删除该选项，是否继续？\",\n      icon: createVNode(ExclamationCircleOutlined),\n\t\t\tokText: \"确定\",\n      cancelText: \"取消\",\n      onOk() {\n        message.success(\"删除成功\");\n      },\n    });\n  };\n\n  const handleCreate = () => {\n\t<% if(includeModifyModal) { _%>\n    model.modalInfo.visible = true;\n    model.modalInfo.title = \"新建\";\n    model.modalInfo.action = \"add\";\n    model.modalInfo.id = undefined;\n\t<% } _%>\n  };\n\n  const handleEdit = (record: typeof model.tableList.value[0]) => {\n\t<% if(includeModifyModal) { _%>\n    model.modalInfo.visible = true;\n    model.modalInfo.title = \"编辑\";\n    model.modalInfo.action = \"edit\";\n    model.modalInfo.id = record.id;\n\t<% } _%>\n  };\n\n  <% if(includeModifyModal) { _%>\n  const handleView = (record: typeof model.tableList.value[0]) => {\n    model.modalInfo.visible = true;\n    model.modalInfo.title = \"查看\";\n    model.modalInfo.action = \"view\";\n    model.modalInfo.id = record.id;\n  };\n\n  const handleModalOk = () => {\n    model.modalInfo.visible = false;\n    service.<%= serviceName %>();\n  };\n\n  const handleModalCancel = () => {\n    model.modalInfo.visible = false;\n  };\n  <% } _%>\n\n  return {\n    model,\n    service,\n    handleClear,\n    handleSearch,\n\t<% if(pagination.show) { _%>\n\thandlePageChange,\n  <% } _%>\n\t<% filters.filter(item => item.component === \"select\" && item.remoteFetch).map(item => { _%> \n\t\thandleSearch<%= item.key.slice(0, 1).toUpperCase() + item.key.slice(1) %>,\n\t<% }) _%>\n\thandleDel,\n\thandleCreate,\n    handleEdit,\n\t<% if(includeModifyModal) { _%>\n\thandleView,\n\thandleModalOk,\n\thandleModalCancel\n\t<% } _%>\n  };\n};\n"
  },
  {
    "path": "materials/blocks/antdv2 增删改查列表页/src/service.ts.ejs",
    "content": "import { <%= locals.api ? funcName : fetchName %> } from \"./api\";\nimport { Model } from \"./model\"; \n\nexport default class Service {\n  private model: Model;\n\n  constructor(model: Model) {\n    this.model = model;\n  }\n\n  async <%= serviceName %>() {\n    this.model.loading.list = true;\n\t\t<% filters.map(item => { _%>\n\t\t\t<% if(item.component === \"range-picker\") { _%>\n\t\t\t\tlet <%= item.key %>Start: string | undefined = undefined;\n\t\t\t\tlet <%= item.key %>End: string | undefined = undefined;\n\t\t\t\tif (\n\t\t\t\tthis.model.filterForm.<%= item.key %> &&\n\t\t\t\tthis.model.filterForm.<%= item.key %>[0]\n\t\t\t\t) {\n\t\t\t\t\t<%= item.key %>Start = `${this.model.filterForm.<%= item.key %>[0]} 00:00:00`;\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\tthis.model.filterForm.<%= item.key %> &&\n\t\t\t\tthis.model.filterForm.<%= item.key %>[1]\n\t\t\t\t) {\n\t\t\t\t\t<%= item.key %>End = `${this.model.filterForm.<%= item.key %>[1]} 23:59:59`;\n\t\t\t\t}\n\t\t\t<% } _%>\n\t\t<% }) _%>\n    const res = await <%= locals.api ? funcName : fetchName %>({\n\t\t\t<% filters.map(item => { _%>\n\t\t\t\t<% if(item.component !== \"range-picker\") { _%>\n\t\t\t\t\t<%= item.key %>: this.model.filterForm.<%= item.key %>,\n\t\t\t\t<% } else { _%>\n\t\t\t\t\t<%= item.key %>Start: <%= item.key %>Start,\n\t\t\t\t\t<%= item.key %>End: <%= item.key %>End,\n\t\t\t\t<% } _%>\n\t\t\t<% }) _%>\n\t\t\t<% if(pagination.show) { _%>\n\t\t\t\t<%= pagination.page %>: this.model.pagination.page,\n\t\t\t\t<%= pagination.size %>: this.model.pagination.pageSize,\n\t\t\t<% } _%>\n\t\t}).finally(() => {\n\t\t\tthis.model.loading.list = false;\n\t\t});\n    this.model.tableList.value = res<%- result %>.map((s) => {\n      return {\n\t\t...s,\n\t\t<% columns.map((item, index) => { _%>\n\t\t\t<%= item.key || `column${index+1}` %>: s.<%= item.key || `column${index+1}` %>,\n\t\t<% }) _%>\n\t\tapiResult: s\n      };\n    });\n\t<% if(pagination.show) { _%>\n\tthis.model.pagination.total = res.<%- pagination.total %>;\n\t<% } _%>\n  }\n\n\t<% filters.filter(item => item.component === \"select\" && item.remoteFetch).map(item => { _%> \n\t\tasync search<%= item.key.slice(0, 1).toUpperCase() + item.key.slice(1) %>(value: string) {\n\t\t\tconst res = await Promise.resolve([{ label: \"1\", value: \"1\" }]);\n\t\t\tthis.model.options.<%= item.key %> = res;\n\t\t}\n\t\t\n\t<% }) _%>\n}\n"
  },
  {
    "path": "materials/blocks/antdv2 增删改查列表页/src/temp.mock.script.ejs",
    "content": ".get(`<%= createBlockPath %>/<%= fetchName %>`, async (ctx, next) => { <%- mockCode %> ctx.body = <%- mockData %>\n})\n"
  },
  {
    "path": "materials/blocks/antdv2 增删改查列表页/src/temp.mock.type.ejs",
    "content": "{\n  code: number;\n\tmsg: string;\n\t<% if (!pagination.show) { _%>\n\tresult: {\n\t\t<% columns.map((item, index) => { _%>\n\t\t\t<%= item.key || `column${index+1}` %>: string;\n\t\t<% }) _%>\n\t}[];\n\t<% } else { _%>\n\t\tresult: {\n\t\t\trecords: {\n\t\t\t\t<% columns.map((item, index) => { _%>\n\t\t\t\t\t<%= item.key || `column${index+1}` %>: string;\n\t\t\t\t<% }) _%>\n\t\t\t}[];\n\t\t\ttotal: number;\n\t\t}\n\t<% } _%>\n}"
  },
  {
    "path": "materials/blocks/react-mvp 模块/config/model.json",
    "content": "{}"
  },
  {
    "path": "materials/blocks/react-mvp 模块/config/preview.json",
    "content": "{\n\t\"title\": \"react-mvp 模块\",\n\t\"description\": \"react-mvp 模块\",\n\t\"img\": \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\",\n\t\"category\": [\n\t\t\"react\",\n\t\t\"mvp\"\n\t]\n}"
  },
  {
    "path": "materials/blocks/react-mvp 模块/config/schema.json",
    "content": "{}"
  },
  {
    "path": "materials/blocks/react-mvp 模块/src/index.tsx.ejs",
    "content": "import React from \"react\";\nimport usePresenter from \"./presenter\";\n\nexport default () => {\n  const presenter = usePresenter();\n  const { model } = presenter;\n  return <div>react mvp</div>;\n};\n"
  },
  {
    "path": "materials/blocks/react-mvp 模块/src/model.ts.ejs",
    "content": "export const useModel = () => {};\n\nexport type Model = ReturnType<typeof useModel>;\n"
  },
  {
    "path": "materials/blocks/react-mvp 模块/src/presenter.tsx.ejs",
    "content": "import { useModel } from \"./model\";\nimport Service from \"./service\";\n\nconst usePresenter = () => {\n  const model = useModel();\n  const service = new Service(model);\n\n  return {\n    model,\n    service,\n  };\n};\n\nexport default usePresenter;\n"
  },
  {
    "path": "materials/blocks/react-mvp 模块/src/service.ts.ejs",
    "content": "import { Model } from \"./model\";\n\nexport default class Service {\n  private model: Model;\n\n  constructor(model: Model) {\n    this.model = model;\n  }\n}\n"
  },
  {
    "path": "materials/blocks/taro-request/config/model.json",
    "content": "{}"
  },
  {
    "path": "materials/blocks/taro-request/config/preview.json",
    "content": "{\n\t\"title\": \"taro-request\",\n\t\"description\": \"taro-request通用封装\",\n\t\"img\": \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\",\n\t\"category\": [\n\t\t\"taro\",\n\t\t\"request\"\n\t]\n}"
  },
  {
    "path": "materials/blocks/taro-request/config/schema.json",
    "content": "{}"
  },
  {
    "path": "materials/blocks/taro-request/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/blocks/taro-request/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/blocks/taro-request/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (context) => {},\n  afterCompile: (constext) => {},\n};\n"
  },
  {
    "path": "materials/blocks/taro-request/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { CompileContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/blocks/taro-request/script/src/main.ts",
    "content": "export const main = 1;\n"
  },
  {
    "path": "materials/blocks/taro-request/src/config.ts.ejs",
    "content": "// 请求连接前缀\nexport const baseUrl =\n  process.env.NODE_ENV === \"production\"\n    ? \"https://xxx.com\"\n    : \"http://localhost:8360\";\n\n// 输出日志信息\nexport const noConsole = false;\n"
  },
  {
    "path": "materials/blocks/taro-request/src/index.ts.ejs",
    "content": "import * as Taro from \"@tarojs/taro\";\nimport * as queryString from \"query-string\";\nimport { baseUrl } from \"./config\";\nimport interceptors from \"./interceptors\";\n\ninterceptors.forEach((interceptorItem) => Taro.addInterceptor(interceptorItem));\n\ninterface OptionsType {\n  method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\";\n  params?: Object;\n  data?: Object;\n  noLoading?: boolean;\n}\nexport const request = <T = any>(\n  url: string,\n  options: OptionsType = {\n    method: \"GET\",\n    params: {},\n    data: {},\n    noLoading: false,\n  }\n) => {\n  if (!options.noLoading) {\n    Taro.showLoading({\n      title: \"加载中\",\n    });\n  }\n  for (const key in options.data) {\n    if (\n      options.data.hasOwnProperty(key) &&\n      (options.data[key] === undefined || options.data[key] == null)\n    ) {\n      delete options.data[key];\n    }\n  }\n  const urlWithParms =\n    url.indexOf(\"?\") > -1\n      ? `${url}&${queryString.stringify(options.params)}`\n      : `${url}?${queryString.stringify(options.params)}`;\n  return Taro.request<T>({\n    url:\n      urlWithParms.indexOf(\"http\") === -1\n        ? `${baseUrl}${urlWithParms}`\n        : urlWithParms,\n    data: {\n      ...options.data,\n    },\n    header: {\n      // \"X-Token\": Taro.getStorageSync(\"token\"),\n      \"Content-Type\": \"application/json\",\n    },\n    method: options.method.toUpperCase() as any,\n  })\n    .then((res) => {\n      return res.data;\n    })\n    .finally(() => {\n      setTimeout(() => {\n        Taro.hideLoading();\n      }, 100);\n    });\n};\n"
  },
  {
    "path": "materials/blocks/taro-request/src/interceptors.ts.ejs",
    "content": "import * as Taro from \"@tarojs/taro\";\n\nconst HTTP_STATUS = {\n  SUCCESS: 200,\n  CREATED: 201,\n  ACCEPTED: 202,\n  CLIENT_ERROR: 400,\n  AUTHENTICATE: 401,\n  FORBIDDEN: 403,\n  NOT_FOUND: 404,\n  SERVER_ERROR: 500,\n  BAD_GATEWAY: 502,\n  SERVICE_UNAVAILABLE: 503,\n  GATEWAY_TIMEOUT: 504,\n};\n\nconst rspInterceptor: Taro.interceptor = (chain) => {\n  const { requestParams } = chain;\n\n  return chain.proceed(requestParams).then((res) => {\n    if (res.statusCode === HTTP_STATUS.BAD_GATEWAY) {\n      return Promise.reject(\"服务端出现了问题\");\n    }\n    if (res.statusCode === HTTP_STATUS.FORBIDDEN) {\n      return Promise.reject(\"没有权限访问\");\n    }\n    if (res.statusCode === HTTP_STATUS.AUTHENTICATE) {\n      return Promise.reject(\"需要鉴权\");\n    }\n    if (res.statusCode === HTTP_STATUS.SUCCESS) {\n      return res;\n    }\n  });\n};\n\nconst interceptors = [rspInterceptor];\n\nexport default interceptors;\n"
  },
  {
    "path": "materials/blocks/vant 表单/config/model.json",
    "content": "{\n\t\"formItems\": []\n}"
  },
  {
    "path": "materials/blocks/vant 表单/config/preview.json",
    "content": "{\n\t\"title\": \"\",\n\t\"description\": \"\",\n\t\"img\": [\n\t\t\"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n\t],\n\t\"category\": [],\n\t\"schema\": \"amis\",\n\t\"scripts\": [\n\t\t{\n\t\t\t\"method\": \"askChatGPT\",\n\t\t\t\"remark\": \"使用 ChatGPT 翻译模版数据里的指定中文字段\"\n\t\t}\n\t]\n}"
  },
  {
    "path": "materials/blocks/vant 表单/config/schema.json",
    "content": "{\n\t\"formSchema\": {\n\t\t\"schema\": {\n\t\t\t\"type\": \"page\",\n\t\t\t\"body\": [\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"form\",\n\t\t\t\t\t\"title\": \"\",\n\t\t\t\t\t\"body\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\"label\": \"defineProps\",\n\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\"name\": \"defineProps\",\n\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\"id\": \"u:9e7d1ee83373\",\n\t\t\t\t\t\t\t\"value\": false\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\"label\": \"defineEmits\",\n\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\"name\": \"defineEmits\",\n\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\"id\": \"u:4ef4be234efc\",\n\t\t\t\t\t\t\t\"value\": false\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"combo\",\n\t\t\t\t\t\t\t\"label\": \"表单项\",\n\t\t\t\t\t\t\t\"name\": \"formItems\",\n\t\t\t\t\t\t\t\"multiple\": true,\n\t\t\t\t\t\t\t\"addable\": true,\n\t\t\t\t\t\t\t\"removable\": true,\n\t\t\t\t\t\t\t\"removableMode\": \"button\",\n\t\t\t\t\t\t\t\"tabsLabelTpl\": \"表单项${index+1}\",\n\t\t\t\t\t\t\t\"addBtn\": {\n\t\t\t\t\t\t\t\t\"label\": \"新增\",\n\t\t\t\t\t\t\t\t\"icon\": \"fa fa-plus\",\n\t\t\t\t\t\t\t\t\"level\": \"primary\",\n\t\t\t\t\t\t\t\t\"size\": \"sm\",\n\t\t\t\t\t\t\t\t\"id\": \"u:47ecb9e15ff1\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"items\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"key\",\n\t\t\t\t\t\t\t\t\t\"placeholder\": \"字段名\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:25b0c7b5e5a0\",\n\t\t\t\t\t\t\t\t\t\"label\": \"字段名（key）\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\"name\": \"type\",\n\t\t\t\t\t\t\t\t\t\"placeholder\": \"选项\",\n\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"string\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"number\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"number\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"boolean\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"string[]\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"string[]\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"number[]\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"number[]\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"boolean[]\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"boolean[]\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"id\": \"u:5bb823bc0afb\",\n\t\t\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\t\t\"label\": \"字段类型\",\n\t\t\t\t\t\t\t\t\t\"value\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"字段可选（字段名字后加?）\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"optional\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:f22b76a31198\",\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\"label\": \"默认值\",\n\t\t\t\t\t\t\t\t\t\"name\": \"defaultValue\",\n\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"\\\"\\\"\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"\\\"\\\"\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"false\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"false\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"true\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"true\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"0\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"0\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"undefined\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"undefined\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"[]\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"[]\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"id\": \"u:d721f505457e\",\n\t\t\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\t\t\"value\": \"\",\n\t\t\t\t\t\t\t\t\t\"creatable\": true\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"flex\",\n\t\t\t\t\t\t\t\t\t\"items\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"container\",\n\t\t\t\t\t\t\t\t\t\t\t\"body\": [\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"name\": \"component\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"placeholder\": \"选项\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"input(van-field)\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"input\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"van-cell(常规表单组件布局无法满足时使用)\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"van-cell\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"van-switch\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"van-switch\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"van-checkbox\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"van-checkbox\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"van-checkbox-group\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"van-checkbox-group\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"van-radio-group\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"van-radio-group\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"van-stepper\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"van-stepper\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"van-uploader\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"van-uploader\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"van-picker\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"van-picker\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"van-datetime-picker\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"van-datetime-picker\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"id\": \"u:995915eabcca\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"组件\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"\"\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t\"size\": \"xs\",\n\t\t\t\t\t\t\t\t\t\t\t\"style\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"position\": \"static\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"display\": \"block\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"flex\": \"1 1 auto\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"flexGrow\": 1,\n\t\t\t\t\t\t\t\t\t\t\t\t\"flexBasis\": \"auto\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"paddingLeft\": \"0px\"\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\"wrapperBody\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"isFixedHeight\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"isFixedWidth\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"u:63cbd01838cb\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"container\",\n\t\t\t\t\t\t\t\t\t\t\t\"body\": [\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"button\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"预览图\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"id\": \"u:421835b9eb42\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"actionType\": \"dialog\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"dialog\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"dialog\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"title\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"body\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"carousel\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"auto\": false,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"thumbMode\": \"contain\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"animation\": \"fade\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"image\": \"https://black-pearl.oss-cn-shenzhen.aliyuncs.com/2023/08/14/df767ebd-1a56-40ee-bb47-f7acbda5a85f.png\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"href\": \"https://black-pearl.oss-cn-shenzhen.aliyuncs.com/2023/08/14/df767ebd-1a56-40ee-bb47-f7acbda5a85f.png\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"image\": \"https://black-pearl.oss-cn-shenzhen.aliyuncs.com/2023/08/14/deb8c82a-7b03-415d-bfd0-372f8a5d9e31.png\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"href\": \"https://black-pearl.oss-cn-shenzhen.aliyuncs.com/2023/08/14/deb8c82a-7b03-415d-bfd0-372f8a5d9e31.png\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"height\": \"300\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"id\": \"u:679ce934b491\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"interval\": 5000,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"duration\": 500,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"alwaysShowArrow\": false,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"controls\": \"arrows\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"controlsTheme\": \"dark\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"actions\": [],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"id\": \"u:92a20653a80f\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${formItems[index].component==='666'}\"\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t\"size\": \"xs\",\n\t\t\t\t\t\t\t\t\t\t\t\"style\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"position\": \"static\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"display\": \"block\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"flex\": \"0 0 auto\"\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\"wrapperBody\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"isFixedHeight\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"isFixedWidth\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"u:e1a77fc17ac2\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"style\": {\n\t\t\t\t\t\t\t\t\t\t\"position\": \"relative\",\n\t\t\t\t\t\t\t\t\t\t\"inset\": \"auto\",\n\t\t\t\t\t\t\t\t\t\t\"flexWrap\": \"nowrap\",\n\t\t\t\t\t\t\t\t\t\t\"alignItems\": \"flex-end\",\n\t\t\t\t\t\t\t\t\t\t\"marginBottom\": \"1.5rem\",\n\t\t\t\t\t\t\t\t\t\t\"paddingLeft\": \"0px\",\n\t\t\t\t\t\t\t\t\t\t\"paddingRight\": \"0px\"\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"id\": \"u:e109a539ee8f\",\n\t\t\t\t\t\t\t\t\t\"isFixedHeight\": false,\n\t\t\t\t\t\t\t\t\t\"isFixedWidth\": false\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"label\",\n\t\t\t\t\t\t\t\t\t\"name\": \"label\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:6496cac4f4b8\",\n\t\t\t\t\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\t\t\t\t\"description\": \"输入框左侧文本\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"placeholder\",\n\t\t\t\t\t\t\t\t\t\"name\": \"placeholder\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:d7f1a8a39449\",\n\t\t\t\t\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\t\t\t\t\"description\": \"输入框占位提示文字\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"required\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"required\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:032dae2bdd71\",\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"是否显示表单必填星号\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"Props （更多组件配置）\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"showMore\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:bb465f530390\",\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"以下组件 props 不修改默认值，对应 props 不会显式出现\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"name\",\n\t\t\t\t\t\t\t\t\t\"name\": \"name\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:8f64b1631d4b\",\n\t\t\t\t\t\t\t\t\t\"description\": \"名称，作为提交表单时的标识符\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!showMore}\",\n\t\t\t\t\t\t\t\t\t\"clearValueOnHidden\": false,\n\t\t\t\t\t\t\t\t\t\"static\": false\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\"label\": \"type\",\n\t\t\t\t\t\t\t\t\t\"name\": \"prop-type\",\n\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"text\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"text\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"id\": \"u:2c327c726ef1\",\n\t\t\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"输入框类型, 支持原生 input 标签的所有 type 属性，额外支持了 digit 类型，默认 text\",\n\t\t\t\t\t\t\t\t\t\"value\": \"\",\n\t\t\t\t\t\t\t\t\t\"creatable\": true,\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!showMore}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\"label\": \"size\",\n\t\t\t\t\t\t\t\t\t\"name\": \"size\",\n\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"large\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"large\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"id\": \"u:8226dd30543a\",\n\t\t\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"大小，可选值为 large\",\n\t\t\t\t\t\t\t\t\t\"value\": \"\",\n\t\t\t\t\t\t\t\t\t\"creatable\": false,\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!showMore}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"maxlength\",\n\t\t\t\t\t\t\t\t\t\"name\": \"maxlength\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:07d46929d8bd\",\n\t\t\t\t\t\t\t\t\t\"description\": \"输入的最大字符数\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!showMore}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"border\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"border\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:c8ffc4fb3136\",\n\t\t\t\t\t\t\t\t\t\"value\": true,\n\t\t\t\t\t\t\t\t\t\"description\": \"是否显示内边框\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!showMore}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"disabled\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"disabled\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:8e7682ebbdf7\",\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"是否禁用输入框\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!showMore}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"readonly\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"readonly\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:51f1dc68ba31\",\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"是否为只读状态，只读状态下无法输入内容\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!showMore}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"colon\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"colon\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:d9d4478d4916\",\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"是否在 label 后面添加冒号\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!showMore}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"center\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"center\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:15bf10ee0f38\",\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"是否使内容垂直居中\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!showMore}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"clearable\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"clearable\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:6c6cb9913893\",\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"是否启用清除图标，点击清除图标后会清空输入框\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!showMore}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"clickable\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"clickable\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:a477d44b7d8b\",\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"是否开启点击反馈\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!showMore}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"is-link\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"is-link\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:7dec0bd94494\",\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"是否展示右侧箭头并开启点击反馈\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!showMore}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"autofocus\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"autofocus\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:e4ed85c736e6\",\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"是否自动聚焦，iOS 系统不支持该属性\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!showMore}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"show-word-limit\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"show-word-limit\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:09de98d0b14f\",\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"是否显示字数统计，需要设置 maxlength 属性\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!showMore}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\"label\": \"arrow-direction\",\n\t\t\t\t\t\t\t\t\t\"name\": \"arrow-direction\",\n\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"left\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"left\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"right\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"right\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"up\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"up\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"down\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"down\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"id\": \"u:861c9d5d39f9\",\n\t\t\t\t\t\t\t\t\t\"value\": \"\",\n\t\t\t\t\t\t\t\t\t\"creatable\": true,\n\t\t\t\t\t\t\t\t\t\"description\": \"箭头方向，可选值为 left up down，默认 right\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!showMore}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\"label\": \"label-align\",\n\t\t\t\t\t\t\t\t\t\"name\": \"label-align\",\n\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"left\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"left\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"center\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"center\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"right\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"right\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"id\": \"u:29bb77848154\",\n\t\t\t\t\t\t\t\t\t\"value\": \"\",\n\t\t\t\t\t\t\t\t\t\"creatable\": true,\n\t\t\t\t\t\t\t\t\t\"description\": \"左侧文本对齐方式，可选值为 center right，默认 left\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!showMore}\",\n\t\t\t\t\t\t\t\t\t\"multiple\": false\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\"label\": \"input-align\",\n\t\t\t\t\t\t\t\t\t\"name\": \"input-align\",\n\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"left\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"left\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"center\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"center\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"right\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"right\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"id\": \"u:5a64d2c0eb4d\",\n\t\t\t\t\t\t\t\t\t\"value\": \"\",\n\t\t\t\t\t\t\t\t\t\"creatable\": true,\n\t\t\t\t\t\t\t\t\t\"description\": \"输入框对齐方式，可选值为 center right\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!showMore}\",\n\t\t\t\t\t\t\t\t\t\"multiple\": false\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"Slots\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"slots\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:678ac90795de\",\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"hidden\": false\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"label slot\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"label-slot\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:549ef5521c55\",\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"自定义输入框左侧文本\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!slots}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"left-icon slot\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"left-icon\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:02a1b49564b8\",\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"自定义输入框头部图标\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!slots}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"right-icon slot\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"right-icon\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:5ce280c3acfe\",\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"自定义输入框尾部图标\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!slots}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"button slot\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"button\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:90291d1eca81\",\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"自定义输入框尾部按钮\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!slots}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"extra slot\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"extra\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:db41c5de7416\",\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"自定义输入框最右侧的额外内容\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!slots}\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"id\": \"u:186f183e9320\",\n\t\t\t\t\t\t\t\"strictMode\": false,\n\t\t\t\t\t\t\t\"syncFields\": [],\n\t\t\t\t\t\t\t\"tabsMode\": true,\n\t\t\t\t\t\t\t\"draggable\": true,\n\t\t\t\t\t\t\t\"draggableTip\": \"可拖动排序\",\n\t\t\t\t\t\t\t\"tabsStyle\": \"line\",\n\t\t\t\t\t\t\t\"deleteBtn\": {\n\t\t\t\t\t\t\t\t\"label\": \"删除\",\n\t\t\t\t\t\t\t\t\"level\": \"default\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\t\"id\": \"u:67967afb0e69\",\n\t\t\t\t\t\"submitText\": \"\"\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"id\": \"u:d87dbf6bf8df\",\n\t\t\t\"pullRefresh\": {\n\t\t\t\t\"disabled\": true\n\t\t\t},\n\t\t\t\"regions\": [\n\t\t\t\t\"body\"\n\t\t\t],\n\t\t\t\"style\": {\n\t\t\t\t\"boxShadow\": \" 0px 0px 0px 0px transparent\"\n\t\t\t},\n\t\t\t\"asideResizor\": false\n\t\t},\n\t\t\"conditionFiles\": {\n\t\t\t\"name\": {\n\t\t\t\t\"value\": \"123\",\n\t\t\t\t\"exclude\": [\n\t\t\t\t\t\"当表单name的值为123,删除这个数组里的文件.ejs\"\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"excludeCompile\": [\n\t\t\t\"不需要编译的文件,不会被删除.ejs\"\n\t\t]\n\t}\n}"
  },
  {
    "path": "materials/blocks/vant 表单/config/viewPrompt.ejs",
    "content": "<%- model %> \r\n将这段 json 中，中文 key 翻译为英文，使用驼峰语法，\r\n返回翻译后的markdown语法的代码块"
  },
  {
    "path": "materials/blocks/vant 表单/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/blocks/vant 表单/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/blocks/vant 表单/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (context) => {},\n  afterCompile: (context) => {\n    context.outputChannel.appendLine(__dirname);\n    context.outputChannel.appendLine(__filename);\n    context.outputChannel.appendLine(process.cwd());\n    context.outputChannel.appendLine(JSON.stringify(context.model));\n  },\n  askChatGPT: async (context) => {\n    const statusBarItem = context.vscode.window.createStatusBarItem(\n      context.vscode.StatusBarAlignment.Left,\n    );\n    statusBarItem.text = '$(sync~spin) Ask ChatGPT...';\n    statusBarItem.show();\n    const res = await context.createChatCompletion({\n      messages: [\n        {\n          role: 'system',\n          content: `你是一个严谨的代码机器人，严格按照输入的要求处理问题`,\n        },\n        {\n          role: 'user',\n          content: `${JSON.stringify(\n            context.model,\n          )} 将这段 json formItems 字段中的 key 字段的值翻译为英文，使用驼峰语法，label、placeholder\n\t\t\t\t\t保留中文。\n\t\t\t\t\t返回翻译后的JSON，不要带其他无关的内容，并且返回的结果使用 JSON.parse 不会报错`,\n        },\n      ],\n      handleChunk: (data) => {\n        // context.outputChannel.append(data.text || '')\n      },\n    });\n    statusBarItem.hide();\n    statusBarItem.dispose();\n    context.outputChannel.appendLine(res);\n    return { ...context.model, ...JSON.parse(res) };\n  },\n};\n"
  },
  {
    "path": "materials/blocks/vant 表单/src/index.vue.ejs",
    "content": "<template>\n  <van-cell-group inset>\n\t\t<% formItems.map(item => { _%>\n\t\t\t<% if(item.component === \"input\"){ _%>\n\t\t\t\t<van-field\n\t\t\t\t\tv-model=\"model.formData.<%= item.key %>\"\n\t\t\t\t\t<% if(item.label){ _%>\n\t\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.name){ _%>\n\t\t\t\t\tname=\"<%= item.name %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item[\"prop-type\"]){ _%>\n\t\t\t\t\ttype=\"<%= item[\"prop-type\"] %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.size){ _%>\n\t\t\t\t\tsize=\"<%= item.size %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.maxlength){ _%>\n\t\t\t\t\tmaxlength=\"<%= item.maxlength %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.placeholder){ _%>\n\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.border === false){ _%>\n\t\t\t\t\t:border=\"false\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.disabled){ _%>\n\t\t\t\t\tdisabled\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.readonly){ _%>\n\t\t\t\t\treadonly\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.colon){ _%>\n\t\t\t\t\tcolon\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.required){ _%>\n\t\t\t\t\trequired\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.center){ _%>\n\t\t\t\t\tcenter\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.clearable){ _%>\n\t\t\t\t\tclearable\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.clickable){ _%>\n\t\t\t\t\tclickable\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item[\"is-link\"]){ _%>\n\t\t\t\t\tis-link\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.autofocus){ _%>\n\t\t\t\t\tautofocus\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item[\"show-word-limit\"]){ _%>\n\t\t\t\t\tshow-word-limit\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item[\"arrow-direction\"]){ _%>\n\t\t\t\t\tarrow-direction=\"<%= item[\"arrow-direction\"] %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item[\"label-align\"]){ _%>\n\t\t\t\t\tlabel-align=\"<%= item[\"label-align\"] %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item[\"input-align\"]){ _%>\n\t\t\t\t\tinput-align=\"<%= item[\"input-align\"] %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t>\n\t\t\t\t\t<% if(item[\"label-slot\"]){ _%>\n\t\t\t\t\t\t<template #label>\n\t\t\t\t\t\t\tlabel-slot\n\t\t\t\t\t\t</template>\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item[\"left-icon\"]){ _%>\n\t\t\t\t\t\t<template #left-icon>\n\t\t\t\t\t\t\tleft-icon\n\t\t\t\t\t\t</template>\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item[\"right-icon\"]){ _%>\n\t\t\t\t\t\t<template #right-icon>\n\t\t\t\t\t\t\tright-icon\n\t\t\t\t\t\t</template>\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item[\"button\"]){ _%>\n\t\t\t\t\t\t<template #button>\n\t\t\t\t\t\t\tbutton\n\t\t\t\t\t\t</template>\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item[\"extra\"]){ _%>\n\t\t\t\t\t\t<template #extra>\n\t\t\t\t\t\t\textra\n\t\t\t\t\t\t</template>\n\t\t\t\t\t<% } _%>\n\t\t\t\t</van-field>\n\t\t\t<% } else if(item.component === \"van-cell\") { _%>\n\t\t\t\t<van-cell>\n\t\t\t\t\t<template #title>\n\t\t\t\t\t\t<label class=\"van-field__label van-field__label--required\"><%= item.label %></label>\n\t\t\t\t\t</template>\n\t\t\t\t\t<template #label>\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t自定义组件\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</template>\n\t\t\t\t</van-cell>\n\t\t\t<% } else { _%>\n\t\t\t\t<van-field\n\t\t\t\t\t<% if(item.component === \"van-picker\" || item.component === \"van-datetime-picker\"){ _%>\n\t\t\t\t\tv-model=\"model.formData.<%= item.key %>\"\n\t\t\t\t\t@click=\"presenter.handle<%= item.key.slice(0, 1).toUpperCase() + item.key.slice(1) %>PickerOpen\"\n\t\t\t\t\tis-link\n      \t\treadonly\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.label){ _%>\n\t\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.name){ _%>\n\t\t\t\t\tname=\"<%= item.name %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item[\"prop-type\"]){ _%>\n\t\t\t\t\ttype=\"<%= item[\"prop-type\"] %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.size){ _%>\n\t\t\t\t\tsize=\"<%= item.size %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.maxlength){ _%>\n\t\t\t\t\tmaxlength=\"<%= item.maxlength %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.placeholder){ _%>\n\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.border === false){ _%>\n\t\t\t\t\t:border=\"false\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.disabled){ _%>\n\t\t\t\t\tdisabled\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.readonly){ _%>\n\t\t\t\t\treadonly\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.colon){ _%>\n\t\t\t\t\tcolon\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.requiredIcon){ _%>\n\t\t\t\t\trequired\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.center){ _%>\n\t\t\t\t\tcenter\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.clearable){ _%>\n\t\t\t\t\tclearable\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.clickable){ _%>\n\t\t\t\t\tclickable\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item[\"is-link\"]){ _%>\n\t\t\t\t\tis-link\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.autofocus){ _%>\n\t\t\t\t\tautofocus\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item[\"show-word-limit\"]){ _%>\n\t\t\t\t\tshow-word-limit\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item[\"arrow-direction\"]){ _%>\n\t\t\t\t\tarrow-direction=\"<%= item[\"arrow-direction\"] %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item[\"label-align\"]){ _%>\n\t\t\t\t\tlabel-align=\"<%= item[\"label-align\"] %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item[\"input-align\"]){ _%>\n\t\t\t\t\tinput-align=\"<%= item[\"input-align\"] %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t>\n\t\t\t\t<% if(item.component === \"van-switch\"){ _%>\n\t\t\t\t\t<template #input>\n\t\t\t\t\t\t<van-switch\n\t\t\t\t\t\t\tv-model=\"model.formData.<%= item.key %>\"\n\t\t\t\t\t\t\tloading\n\t\t\t\t\t\t\tdisabled\n\t\t\t\t\t\t\tsize=\"20\"\n\t\t\t\t\t\t\tactive-color=\"#1989fa\"\n\t\t\t\t\t\t\tinactive-color=\"white\"\n\t\t\t\t\t\t\tactive-value=\"true\"\n\t\t\t\t\t\t\tinactive-value=\"false\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t</template>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item.component === \"van-checkbox\"){ _%>\n\t\t\t\t\t<template #input>\n\t\t\t\t\t\t<van-checkbox v-model=\"model.formData.<%= item.key %>\" shape=\"square\" />\n\t\t\t\t\t</template>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item.component === \"van-checkbox-group\"){ _%>\n\t\t\t\t\t<template #input>\n\t\t\t\t\t\t<van-checkbox-group v-model=\"model.formData.<%= item.key %>\" direction=\"horizontal\">\n\t\t\t\t\t\t\t<van-checkbox\n\t\t\t\t\t\t\t\tv-for=\"item in model.options.<%= item.key %>\"\n\t\t\t\t\t\t\t\t:key=\"item.value\"\n\t\t\t\t\t\t\t\t:name=\"item.value\"\n\t\t\t\t\t\t\t\tshape=\"square\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{{ item.label }}\n\t\t\t\t\t\t\t</van-checkbox>\n\t\t\t\t\t\t</van-checkbox-group>\n\t\t\t\t\t</template>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item.component === \"van-radio-group\"){ _%>\n\t\t\t\t\t<template #input>\n\t\t\t\t\t\t<van-radio-group v-model=\"model.formData.<%= item.key %>\" direction=\"horizontal\">\n\t\t\t\t\t\t\t<van-radio v-for=\"item in model.options.<%= item.key %>\" :key=\"item.value\" :name=\"item.value\">\n\t\t\t\t\t\t\t\t{{ item.label }}\n\t\t\t\t\t\t\t</van-radio>\n\t\t\t\t\t\t</van-radio-group>\n\t\t\t\t\t</template>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item.component === \"van-stepper\"){ _%>\n\t\t\t\t\t<template #input>\n\t\t\t\t\t\t<van-stepper v-model=\"model.formData.<%= item.key %>\" />\n\t\t\t\t\t</template>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item.component === \"van-uploader\"){ _%>\n\t\t\t\t\t<template #input>\n\t\t\t\t\t\t<van-uploader />\n\t\t\t\t\t</template>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item.component === \"van-picker\"){ _%>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item.component === \"van-datetime-picker\"){ _%>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item[\"label-slot\"]){ _%>\n\t\t\t\t\t<template #label>\n\t\t\t\t\t\tlabel-slot\n\t\t\t\t\t</template>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item[\"left-icon\"]){ _%>\n\t\t\t\t\t<template #left-icon>\n\t\t\t\t\t\tleft-icon\n\t\t\t\t\t</template>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item[\"right-icon\"]){ _%>\n\t\t\t\t\t<template #right-icon>\n\t\t\t\t\t\tright-icon\n\t\t\t\t\t</template>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item[\"button\"]){ _%>\n\t\t\t\t\t<template #button>\n\t\t\t\t\t\tbutton\n\t\t\t\t\t</template>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item[\"extra\"]){ _%>\n\t\t\t\t\t<template #extra>\n\t\t\t\t\t\textra\n\t\t\t\t\t</template>\n\t\t\t\t<% } _%>\n\t\t\t\t</van-field>\n\t\t\t<% } _%>\n\t\t<% }) _%>\n\t\t<% formItems.filter(s => s.component === \"van-picker\" || s.component === \"van-datetime-picker\").map(item => { _%>\n\t\t\t<% if(item.component === \"van-picker\"){ _%>\t\n\t\t\t\t<van-popup v-model:show=\"model.picker.<%= item.key %>.visible\" position=\"bottom\">\n\t\t\t\t\t<van-picker\n\t\t\t\t\t\t:columns=\"model.picker.<%= item.key %>.columns\"\n\t\t\t\t\t\t@confirm=\"presenter.handle<%= item.key.slice(0, 1).toUpperCase() + item.key.slice(1) %>PickerConfirm\"\n\t\t\t\t\t\t@cancel=\"presenter.handle<%= item.key.slice(0, 1).toUpperCase() + item.key.slice(1) %>PickerCancel\"\n\t\t\t\t\t/>\n\t\t\t\t</van-popup>\n\t\t\t<% } _%>\n\t\t\t<% if(item.component === \"van-datetime-picker\"){ _%>\t\n\t\t\t\t<van-popup v-model:show=\"model.picker.<%= item.key %>.visible\" position=\"bottom\">\n\t\t\t\t\t<van-datetime-picker\n\t\t\t\t\t\ttype=\"time\"\n\t\t\t\t\t\t@confirm=\"presenter.handle<%= item.key.slice(0, 1).toUpperCase() + item.key.slice(1) %>PickerConfirm\"\n\t\t\t\t\t\t@cancel=\"presenter.handle<%= item.key.slice(0, 1).toUpperCase() + item.key.slice(1) %>PickerCancel\"\n\t\t\t\t\t/>\n\t\t\t\t</van-popup>\n\t\t\t<% } _%>\n\t\t<% }) _%>\n  </van-cell-group>\n</template>\n<script lang=\"ts\" setup>\n<% if(defineProps || defineEmits){ _%>\nimport {<% if(defineProps){ %>defineProps,<% } %> <% if(defineEmits){ %>defineEmits<% } %> } from 'vue'\n<% } _%>\nimport { usePresenter } from './presenter'\n<% if(defineProps){ %>\ninterface IProps {\n  visible: boolean\n}\n<% } _%>\n<% if(defineEmits){ %>\ninterface IEmit {\n  (event: 'update', id: number): void\n}\n<% } %>\n<% if(defineProps){ %>\nconst props = defineProps<IProps>()\n<% } _%>\n<% if(defineEmits){ %>\nconst emit = defineEmits<IEmit>()\n<% } _%>\n\nconst presenter = usePresenter(<% if(defineProps){ %>props,<% } _%> <% if(defineEmits){ %>emit<% } %>)\nconst { model } = presenter\n</script>\n"
  },
  {
    "path": "materials/blocks/vant 表单/src/model.ts.ejs",
    "content": "import { reactive } from 'vue'\n\nexport interface IFormData {\n\t<% formItems.map(item => { _%>\n\t\t<%= item.key %><% if(item.optional){ _%>?<% } _%>: <%= item.type %>;\n\t<% }) _%>\n}\n\nconst defaultFormData: IFormData = {\n\t<% formItems.map(item => { _%>\n\t\t<%= item.key %>: <%- item.defaultValue || '\\'\\'' %>,\n\t<% }) _%>\n};\n\n<% if(formItems.some(s => s.component === \"van-picker\" || s.component === \"van-datetime-picker\")){ %>\ninterface IPicker {\n\t<% formItems.filter(s => s.component === \"van-picker\" || s.component === \"van-datetime-picker\").map(item => { _%>\n\t\t<% if(item.component === \"van-picker\"){ %>\t\n\t\t\t<%= item.key %>: { visible: boolean; columns: string[] }\n\t\t<% } _%>\n\t\t<% if(item.component === \"van-datetime-picker\"){ %>\t\n\t\t\t<%= item.key %>: { visible: boolean }\n\t\t<% } _%>\n\t<% }) _%>\n}\n<% } %>\n\n\n<% if(formItems.some(s => s.component === \"van-checkbox-group\" || s.component === \"van-radio-group\")){ %>\ninterface IOptionItem {\n  label: string;\n  value: string;\n}\n\ninterface IOptions {\n  <% formItems.filter(s => s.component === \"van-checkbox-group\" || s.component === \"van-radio-group\").map(item => { _%>\n\t\t<%= item.key %>: IOptionItem[];\n\t<% }) _%>\n}\n\nconst defaultOptions: IOptions = {\n  <% formItems.filter(s => s.component === \"van-checkbox-group\" || s.component === \"van-radio-group\").map(item => { _%>\n\t\t<%= item.key %>: [],\n\t<% }) _%>\n};\n<% } %>\n\nexport const useModel = () => {\n  const formData = reactive<IFormData>({ ...defaultFormData });\n\t<% if(formItems.some(s => s.component === \"van-checkbox-group\" || s.component === \"van-radio-group\")){ _%>\n  const options = reactive<IOptions>({ ...defaultOptions });\n\t<% } _%>\n\t<% if(formItems.some(s => s.component === \"van-picker\" || s.component === \"van-datetime-picker\")){ %>\n\t\tconst picker = reactive<IPicker>({\n\t\t\t<% formItems.filter(s => s.component === \"van-picker\" || s.component === \"van-datetime-picker\").map(item => { _%>\n\t\t\t\t<% if(item.component === \"van-picker\"){ %>\t\n\t\t\t\t\t<%= item.key %>: {\n\t\t\t\t\t\tvisible: false,\n\t\t\t\t\t\tcolumns: []\n\t\t\t\t\t},\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item.component === \"van-datetime-picker\"){ %>\t\n\t\t\t\t\t<%= item.key %>: {\n\t\t\t\t\t\tvisible: false\n\t\t\t\t\t}\n\t\t\t\t<% } _%>\n\t\t\t<% }) _%>\n\t\t})\n\t<% } %>\n\n  return { \n\t\tformData, \n\t\t<% if(formItems.some(s => s.component === \"van-checkbox-group\" || s.component === \"van-radio-group\")){ _%>\n\t\toptions,\n\t\t<% } _%>\n\t\t<% if(formItems.some(s => s.component === \"van-picker\" || s.component === \"van-datetime-picker\")){ _%>\n\t\tpicker\n\t\t<% } %>\n\t};\n};\n\nexport type Model = ReturnType<typeof useModel>;\n"
  },
  {
    "path": "materials/blocks/vant 表单/src/presenter.tsx.ejs",
    "content": "import Service from './service'\nimport { useModel } from './model'\n<% if(defineProps){ %>\ninterface IProps {\n  visible: boolean\n}\n<% } %>\n<% if(defineEmits){ %>\ninterface IEmit {\n  (event: 'update', id: number): void\n}\n<% } %>\nexport const usePresenter = (<% if(defineProps){ %>props: IProps,<% } %> <% if(defineEmits){ %>emit: IEmit<% } %>) => {\n  const model = useModel()\n  const service = new Service(model)\n\n\t<% formItems.filter(s => s.component === \"van-picker\" || s.component === \"van-datetime-picker\").map(item => { _%>\n\t\tconst handle<%= item.key.slice(0, 1).toUpperCase() + item.key.slice(1) %>PickerOpen = () => {\n\t\t\tmodel.picker.<%= item.key %>.visible = true\n\t\t}\n\t\n\t\tconst handle<%= item.key.slice(0, 1).toUpperCase() + item.key.slice(1) %>PickerCancel = () => {\n\t\t\tmodel.picker.<%= item.key %>.visible = false\n\t\t}\n\t\n\t\tconst handle<%= item.key.slice(0, 1).toUpperCase() + item.key.slice(1) %>PickerConfirm = (value: string) => {\n\t\t\tmodel.picker.<%= item.key %>.visible = false\n\t\t\tmodel.formData.<%= item.key %> = value\n\t\t}\n\t<% }) _%>\n\n  const handleSubmit = () => {}\n\n  const handleCancel = () => {}\n\n  return {\n    model,\n    service,\n    handleSubmit,\n    handleCancel,\n\t\t<% formItems.filter(s => s.component === \"van-picker\" || s.component === \"van-datetime-picker\").map(item => { _%>\n\t\t\thandle<%= item.key.slice(0, 1).toUpperCase() + item.key.slice(1) %>PickerOpen,\n\t\t\thandle<%= item.key.slice(0, 1).toUpperCase() + item.key.slice(1) %>PickerCancel,\n\t\t\thandle<%= item.key.slice(0, 1).toUpperCase() + item.key.slice(1) %>PickerConfirm,\n\t\t<% }) _%>\n  }\n}\n"
  },
  {
    "path": "materials/blocks/vant 表单/src/service.ts.ejs",
    "content": "import { Model } from \"./model\";\n\nexport default class Service {\n  private model: Model;\n\n  constructor(model: Model) {\n    this.model = model;\n  }\n\n  async submit() {\n    const data = {\n\t\t\t<% formItems.map(item => { _%>\n\t\t\t\t<%= item.key %>: this.model.formData.<%= item.key %>,\n\t\t\t<% }) _%>\n    };\n    await Promise.resolve(data);\n  }\n}\n"
  },
  {
    "path": "materials/blocks/vue-mvp 模块/config/model.json",
    "content": "{}"
  },
  {
    "path": "materials/blocks/vue-mvp 模块/config/preview.json",
    "content": "{\n\t\"title\": \"vue-mvp 模块\",\n\t\"description\": \"vue-mvp 模块\",\n\t\"img\": \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\",\n\t\"category\": [\n\t\t\"vue\",\n\t\t\"vue3\",\n\t\t\"mvp\"\n\t]\n}"
  },
  {
    "path": "materials/blocks/vue-mvp 模块/config/schema.json",
    "content": "{}"
  },
  {
    "path": "materials/blocks/vue-mvp 模块/src/index.tsx.ejs",
    "content": "import { defineComponent } from \"vue\";\nimport { usePresenter } from \"./presenter\";\n\nconst Page = defineComponent({\n  setup() {\n    const presenter = usePresenter();\n    const { model } = presenter;\n\n    return { model, presenter };\n  },\n  render() {\n    return <div>vue mvp</div>;\n  },\n});\nexport default Page;\n"
  },
  {
    "path": "materials/blocks/vue-mvp 模块/src/model.ts.ejs",
    "content": "import { reactive } from \"vue\";\n\nexport const useModel = () => {\n  return {};\n};\n\nexport type Model = ReturnType<typeof useModel>;\n"
  },
  {
    "path": "materials/blocks/vue-mvp 模块/src/presenter.ts.ejs",
    "content": "import Service from \"./service\";\nimport { useModel } from \"./model\";\n\nexport const usePresenter = () => {\n  const model = useModel();\n  const service = new Service(model);\n\n  return {\n    model,\n    service,\n  };\n};\n"
  },
  {
    "path": "materials/blocks/vue-mvp 模块/src/service.ts.ejs",
    "content": "import { Model } from \"./model\";\n\nexport default class Service {\n  private model: Model;\n\n  constructor(model: Model) {\n    this.model = model;\n  }\n}\n"
  },
  {
    "path": "materials/blocks/vue2-mvp 模块/config/model.json",
    "content": "{}"
  },
  {
    "path": "materials/blocks/vue2-mvp 模块/config/preview.json",
    "content": "{\n\t\"title\": \"vue2-mvp 模块\",\n\t\"description\": \"vue2-mvp 模块\",\n\t\"img\": \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\",\n\t\"category\": [\n\t\t\"vue\",\n\t\t\"vue2\",\n\t\t\"mvp\"\n\t]\n}"
  },
  {
    "path": "materials/blocks/vue2-mvp 模块/config/schema.json",
    "content": "{}"
  },
  {
    "path": "materials/blocks/vue2-mvp 模块/src/index.tsx.ejs",
    "content": "import { defineComponent } from \"@vue/composition-api\";\nimport { usePresenter } from \"./presenter\";\n\nconst Index = defineComponent({\n  setup() {\n    const presenter = usePresenter();\n    const { model } = presenter;\n\n    return { model, presenter };\n  },\n  render() {\n    return <div>vue2 mvp</div>;\n  }\n});\nexport default Index;\n"
  },
  {
    "path": "materials/blocks/vue2-mvp 模块/src/model.ts.ejs",
    "content": "import { reactive } from \"@vue/composition-api\";\n\nexport const useModel = () => {\n  return {};\n};\n\nexport type Model = ReturnType<typeof useModel>;\n"
  },
  {
    "path": "materials/blocks/vue2-mvp 模块/src/presenter.ts.ejs",
    "content": "import Service from \"./service\";\nimport { useModel } from \"./model\";\n\nexport const usePresenter = () => {\n  const model = useModel();\n  const service = new Service(model);\n\n  return {\n    model\n  };\n};\n"
  },
  {
    "path": "materials/blocks/vue2-mvp 模块/src/service.ts.ejs",
    "content": "import { Model } from \"./model\";\n\nexport default class Service {\n  private model: Model;\n\n  constructor(model: Model) {\n    this.model = model;\n  }\n}\n"
  },
  {
    "path": "materials/blocks/测试使用 jsx 作为模版引擎/config/model.json",
    "content": "{\n  \"filters\": [],\n  \"columns\": [],\n  \"pagination\": {\n    \"show\": true,\n    \"page\": \"page\",\n    \"size\": \"size\",\n    \"total\": \"result.total\"\n  },\n  \"includeModifyModal\": false,\n  \"fetchName\": \"fetchTableList\",\n  \"result\": \"[\\\"result\\\"][\\\"records\\\"]\",\n  \"serviceName\": \"getTableList\"\n}"
  },
  {
    "path": "materials/blocks/测试使用 jsx 作为模版引擎/config/preview.json",
    "content": "{\n\t\"title\": \"\",\n\t\"description\": \"\",\n\t\"img\": \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\",\n\t\"category\": [],\n\t\"schema\": \"amis\",\n\t\"scripts\": [\n\t\t{\n\t\t\t\"method\": \"initFiltersFromImage\",\n\t\t\t\"remark\": \"使用截图初始化查询条件\"\n\t\t},\n\t\t{\n\t\t\t\"method\": \"initFiltersFromText\",\n\t\t\t\"remark\": \"使用文本初始化查询条件\"\n\t\t},\n\t\t{\n\t\t\t\"method\": \"initColumnsFromText\",\n\t\t\t\"remark\": \"使用文本初始化表格\"\n\t\t},\n\t\t{\n\t\t\t\"method\": \"initColumnsFromImage\",\n\t\t\t\"remark\": \"使用截图初始化表格\"\n\t\t},\n\t\t{\n\t\t\t\"method\": \"askChatGPT\",\n\t\t\t\"remark\": \"使用 ChatGPT 翻译模版数据里的指定中文字段\"\n\t\t}\n\t]\n}"
  },
  {
    "path": "materials/blocks/测试使用 jsx 作为模版引擎/config/schema.json",
    "content": "{\n\t\"formSchema\": {\n\t\t\"schema\": {\n\t\t\t\"type\": \"page\",\n\t\t\t\"body\": [\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"form\",\n\t\t\t\t\t\"title\": \"\",\n\t\t\t\t\t\"body\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"combo\",\n\t\t\t\t\t\t\t\"label\": \"查询条件\",\n\t\t\t\t\t\t\t\"name\": \"filters\",\n\t\t\t\t\t\t\t\"multiple\": true,\n\t\t\t\t\t\t\t\"addable\": true,\n\t\t\t\t\t\t\t\"removable\": true,\n\t\t\t\t\t\t\t\"removableMode\": \"icon\",\n\t\t\t\t\t\t\t\"addBtn\": {\n\t\t\t\t\t\t\t\t\"label\": \"新增\",\n\t\t\t\t\t\t\t\t\"icon\": \"fa fa-plus\",\n\t\t\t\t\t\t\t\t\"level\": \"primary\",\n\t\t\t\t\t\t\t\t\"size\": \"sm\",\n\t\t\t\t\t\t\t\t\"id\": \"u:47ecb9e15ff1\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"items\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"key\",\n\t\t\t\t\t\t\t\t\t\"placeholder\": \"字段名\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:25b0c7b5e5a0\",\n\t\t\t\t\t\t\t\t\t\"label\": \"字段名（key）\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"label\",\n\t\t\t\t\t\t\t\t\t\"name\": \"label\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:6496cac4f4b8\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\"name\": \"component\",\n\t\t\t\t\t\t\t\t\t\"placeholder\": \"选项\",\n\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"input\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"input\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"select\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"select\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"id\": \"u:995915eabcca\",\n\t\t\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\t\t\"label\": \"组件\",\n\t\t\t\t\t\t\t\t\t\"value\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"placeholder\",\n\t\t\t\t\t\t\t\t\t\"name\": \"placeholder\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:d7f1a8a39449\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"id\": \"u:186f183e9320\",\n\t\t\t\t\t\t\t\"strictMode\": false,\n\t\t\t\t\t\t\t\"syncFields\": [],\n\t\t\t\t\t\t\t\"tabsMode\": true,\n\t\t\t\t\t\t\t\"draggable\": true,\n\t\t\t\t\t\t\t\"draggableTip\": \"可拖动排序\",\n\t\t\t\t\t\t\t\"tabsStyle\": \"line\",\n\t\t\t\t\t\t\t\"tabsLabelTpl\": \"表单项${index+1}\",\n\t\t\t\t\t\t\t\"multiLine\": true,\n\t\t\t\t\t\t\t\"noBorder\": false\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"combo\",\n\t\t\t\t\t\t\t\"label\": \"表格\",\n\t\t\t\t\t\t\t\"name\": \"columns\",\n\t\t\t\t\t\t\t\"multiple\": true,\n\t\t\t\t\t\t\t\"addable\": true,\n\t\t\t\t\t\t\t\"removable\": true,\n\t\t\t\t\t\t\t\"removableMode\": \"button\",\n\t\t\t\t\t\t\t\"addBtn\": {\n\t\t\t\t\t\t\t\t\"label\": \"新增\",\n\t\t\t\t\t\t\t\t\"icon\": \"fa fa-plus\",\n\t\t\t\t\t\t\t\t\"level\": \"primary\",\n\t\t\t\t\t\t\t\t\"size\": \"sm\",\n\t\t\t\t\t\t\t\t\"id\": \"u:1e8070edc3d3\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"items\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"title\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:152dd82b82f9\",\n\t\t\t\t\t\t\t\t\t\"label\": \"title\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"dataIndex\",\n\t\t\t\t\t\t\t\t\t\"name\": \"dataIndex\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:ecc7298e0550\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"key\",\n\t\t\t\t\t\t\t\t\t\"name\": \"key\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:fbaa95c3f15d\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"width\",\n\t\t\t\t\t\t\t\t\t\"name\": \"width\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:b143127e097b\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"自定义插槽\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"slot\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:ee1ce1faee0b\",\n\t\t\t\t\t\t\t\t\t\"value\": false\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"id\": \"u:9b9fb0cf38f9\",\n\t\t\t\t\t\t\t\"strictMode\": true,\n\t\t\t\t\t\t\t\"syncFields\": [],\n\t\t\t\t\t\t\t\"tabsMode\": true,\n\t\t\t\t\t\t\t\"draggable\": true,\n\t\t\t\t\t\t\t\"draggableTip\": \"可拖动排序\",\n\t\t\t\t\t\t\t\"tabsStyle\": \"line\",\n\t\t\t\t\t\t\t\"deleteBtn\": {\n\t\t\t\t\t\t\t\t\"label\": \"删除\",\n\t\t\t\t\t\t\t\t\"level\": \"default\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"tabsLabelTpl\": \"列${index+1}\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"fieldset\",\n\t\t\t\t\t\t\t\"title\": \"分页参数\",\n\t\t\t\t\t\t\t\"collapsable\": true,\n\t\t\t\t\t\t\t\"body\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"是否分页\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"pagination.show\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:6c70041d5143\",\n\t\t\t\t\t\t\t\t\t\"value\": true,\n\t\t\t\t\t\t\t\t\t\"className\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"查询接口页数参数字段名\",\n\t\t\t\t\t\t\t\t\t\"name\": \"pagination.page\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:cbbf6853cf64\",\n\t\t\t\t\t\t\t\t\t\"value\": \"page\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"查询接口每页数据行数参数字段名\",\n\t\t\t\t\t\t\t\t\t\"name\": \"pagination.size\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:a8fae66fa927\",\n\t\t\t\t\t\t\t\t\t\"value\": \"size\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"接口返回总数据量字段 PATH\",\n\t\t\t\t\t\t\t\t\t\"name\": \"pagination.total\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:e1cd979c7ee8\",\n\t\t\t\t\t\t\t\t\t\"value\": \"result.total\",\n\t\t\t\t\t\t\t\t\t\"themeCss\": {\n\t\t\t\t\t\t\t\t\t\t\"inputControlClassName\": {\n\t\t\t\t\t\t\t\t\t\t\t\"padding-and-margin:default\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"marginBottom\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"marginTop\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"marginRight\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"marginLeft\": \"\"\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"id\": \"u:0f1bd8fc2f2b\",\n\t\t\t\t\t\t\t\"collapsed\": true,\n\t\t\t\t\t\t\t\"headingClassName\": \"\",\n\t\t\t\t\t\t\t\"bodyClassName\": \"p\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"fieldset\",\n\t\t\t\t\t\t\t\"title\": \"请求方法\",\n\t\t\t\t\t\t\t\"collapsable\": true,\n\t\t\t\t\t\t\t\"body\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"请求名称\",\n\t\t\t\t\t\t\t\t\t\"name\": \"fetchName\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:a3e712484fae\",\n\t\t\t\t\t\t\t\t\t\"value\": \"fetchTableList\",\n\t\t\t\t\t\t\t\t\t\"description\": \"追加了YAPI数据则不使用此参数\",\n\t\t\t\t\t\t\t\t\t\"themeCss\": {\n\t\t\t\t\t\t\t\t\t\t\"labelClassName\": {\n\t\t\t\t\t\t\t\t\t\t\t\"padding-and-margin:default\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"marginTop\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"marginRight\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"marginBottom\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"marginLeft\": \"\"\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"labelClassName\": \"labelClassName-a3e712484fae\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"接口数据字段 PATH\",\n\t\t\t\t\t\t\t\t\t\"name\": \"result\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:8c082acf7db2\",\n\t\t\t\t\t\t\t\t\t\"value\": \"[\\\"result\\\"][\\\"records\\\"]\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"service方法名\",\n\t\t\t\t\t\t\t\t\t\"name\": \"serviceName\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:cfbbdd07366b\",\n\t\t\t\t\t\t\t\t\t\"value\": \"getTableList\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"id\": \"u:382f8cdf59a6\",\n\t\t\t\t\t\t\t\"collapsed\": true,\n\t\t\t\t\t\t\t\"className\": \"\",\n\t\t\t\t\t\t\t\"headingClassName\": \"\",\n\t\t\t\t\t\t\t\"bodyClassName\": \"p-r p-l p-b\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"fieldset\",\n\t\t\t\t\t\t\t\"title\": \"新增/编辑弹框\",\n\t\t\t\t\t\t\t\"collapsable\": true,\n\t\t\t\t\t\t\t\"body\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"是否包含弹框\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"includeModifyModal\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:03957070af9e\",\n\t\t\t\t\t\t\t\t\t\"value\": false\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"combo\",\n\t\t\t\t\t\t\t\t\t\"label\": \"表单项\",\n\t\t\t\t\t\t\t\t\t\"name\": \"modifyModal.formItems\",\n\t\t\t\t\t\t\t\t\t\"multiple\": true,\n\t\t\t\t\t\t\t\t\t\"addable\": true,\n\t\t\t\t\t\t\t\t\t\"removable\": true,\n\t\t\t\t\t\t\t\t\t\"removableMode\": \"icon\",\n\t\t\t\t\t\t\t\t\t\"strictMode\": false,\n\t\t\t\t\t\t\t\t\t\"addBtn\": {\n\t\t\t\t\t\t\t\t\t\t\"label\": \"新增\",\n\t\t\t\t\t\t\t\t\t\t\"icon\": \"fa fa-plus\",\n\t\t\t\t\t\t\t\t\t\t\"level\": \"primary\",\n\t\t\t\t\t\t\t\t\t\t\"size\": \"sm\",\n\t\t\t\t\t\t\t\t\t\t\"id\": \"u:86cc27b6a663\"\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"items\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"key\",\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"u:62cc1cf36c73\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"字段名（key）\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"type\",\n\t\t\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"string\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"number\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"number\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"boolean\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"Dayjs\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"Dayjs\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"string[]\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"string[]\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"number[]\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"number[]\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"boolean[]\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"boolean[]\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"[Dayjs,Dayjs]\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"[Dayjs,Dayjs]\"\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"u:b165c75e5e1a\",\n\t\t\t\t\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"字段类型\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"字段可选\",\n\t\t\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"optional\",\n\t\t\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"u:68fc4c85fb03\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"字段名字后加?\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"defaultValue\",\n\t\t\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"\\\"\\\"\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"\\\"\\\"\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"false\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"false\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"true\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"true\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"0\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"0\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"undefined\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"undefined\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"[]\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"[]\"\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"u:379ea92fb3c6\",\n\t\t\t\t\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"默认值\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"component\",\n\t\t\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"input\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"input\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"input-password\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"input-password\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"input-number\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"input-number\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"textarea\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"textarea\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"select\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"select\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"radio-group\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"radio-group\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"checkbox-group\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"checkbox-group\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"switch\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"switch\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"date-picker\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"date-picker\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"time-ticker\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"time-picker\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"range-picker\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"range-picker\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"transfer\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"transfer\"\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"u:7932ea3b05da\",\n\t\t\t\t\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"组件\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"label\",\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"u:5bb237f20098\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"label\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"placeholder\",\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"u:580898257491\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"placeholder\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"required\",\n\t\t\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"required\",\n\t\t\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"u:559dbdbb01da\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"验证规则加required\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"message\",\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"u:55013279d659\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"校验失败 message\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"不能为空\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"更多组件配置\",\n\t\t\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"showMore\",\n\t\t\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"u:67e0cb5b7496\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"labelInValue\",\n\t\t\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"labelInValue\",\n\t\t\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"u:7fd6f1b233d9\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"是否把每个选项的 label 包装到 value 中\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'select'}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"mode\",\n\t\t\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"multiple\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"multiple\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"tags\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"tags\"\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"mode\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"设置 Select 的模式为多选或标签\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'select'}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"optionFilterProp\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"optionFilterProp\",\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"搜索时过滤对应的 option 属性\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"label\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'select'}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"showSearch\",\n\t\t\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"showSearch\",\n\t\t\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"使单选模式可搜索\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'select'}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"hideArrow\",\n\t\t\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"hideArrow\",\n\t\t\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"是否隐藏下拉小箭头\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'select'}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"maxlength\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"maxlength\",\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"最大长度\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'input' && modifyModal.formItems[index].component !== 'input-password' && modifyModal.formItems[index].component !== 'textarea')}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"showCount\",\n\t\t\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"showCount\",\n\t\t\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"是否展示字数\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'input' && modifyModal.formItems[index].component !== 'input-password' && modifyModal.formItems[index].component !== 'textarea')}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"max\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"max\",\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"最大值\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'input-number'}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"min\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"min\",\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"最小值\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'input-number'}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"step\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"step\",\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"每次改变步数，可以为小数\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'input-number'}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"checkedChildren\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"checkedChildren\",\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"选中时的内容\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'switch'}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"unCheckedChildren\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"unCheckedChildren\",\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"非选中时的内容\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'switch'}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"checkedValue\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"checkedValue\",\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"选中时的值\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'switch'}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"unCheckedValue\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"unCheckedValue\",\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"非选中时的值\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'switch'}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"picker\",\n\t\t\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"date\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"date\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"week\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"week\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"month\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"month\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"quarter\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"quarter\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"year\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"year\"\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"picker\",\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"设置选择器类型\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'date-picker' && modifyModal.formItems[index].component !== 'range-picker')}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"showTime\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"showTime\",\n\t\t\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"增加时间选择功能\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'date-picker' && modifyModal.formItems[index].component !== 'range-picker' || modifyModal.formItems[index].picker !== 'date')}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"showNow\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"showNow\",\n\t\t\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"当设定了 showTime 的时候，面板是否显示“此刻”按钮\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'date-picker' && modifyModal.formItems[index].component !== 'range-picker' || modifyModal.formItems[index].picker !== 'date')}\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"showToday\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"showToday\",\n\t\t\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"是否展示“今天”按钮\",\n\t\t\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'date-picker' && modifyModal.formItems[index].component !== 'range-picker' || modifyModal.formItems[index].picker !== 'date')}\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"syncFields\": [],\n\t\t\t\t\t\t\t\t\t\"tabsMode\": true,\n\t\t\t\t\t\t\t\t\t\"draggable\": true,\n\t\t\t\t\t\t\t\t\t\"draggableTip\": \"可拖动排序\",\n\t\t\t\t\t\t\t\t\t\"tabsStyle\": \"line\",\n\t\t\t\t\t\t\t\t\t\"tabsLabelTpl\": \"表单项${index+1}\",\n\t\t\t\t\t\t\t\t\t\"multiLine\": true,\n\t\t\t\t\t\t\t\t\t\"noBorder\": false,\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!includeModifyModal}\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"bodyClassName\": \"p\",\n\t\t\t\t\t\t\t\"collapsed\": true\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\t\"submitText\": \"\"\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"pullRefresh\": {\n\t\t\t\t\"disabled\": true\n\t\t\t},\n\t\t\t\"regions\": [\n\t\t\t\t\"body\"\n\t\t\t],\n\t\t\t\"style\": {\n\t\t\t\t\"boxShadow\": \" 0px 0px 0px 0px transparent\"\n\t\t\t},\n\t\t\t\"asideResizor\": false\n\t\t}\n\t},\n\t\"conditionFiles\": {\n\t\t\"includeModifyModal\": {\n\t\t\t\"value\": false,\n\t\t\t\"exclude\": [\n\t\t\t\t\"/ModifyModal/index.vue.ejs\",\n\t\t\t\t\"/ModifyModal/model.ts.ejs\",\n\t\t\t\t\"/ModifyModal/presenter.tsx.ejs\",\n\t\t\t\t\"/ModifyModal/presenter.ts.ejs\",\n\t\t\t\t\"/ModifyModal/service.ts.ejs\"\n\t\t\t]\n\t\t}\n\t},\n\t\"excludeCompile\": [\n\t\t\"temp.mock.script.ejs\"\n\t]\n}"
  },
  {
    "path": "materials/blocks/测试使用 jsx 作为模版引擎/config/schema.ts",
    "content": "export type PageConfig = {\n  filters: {\n    component: string;\n    /**\n     * @description 翻译成英文，驼峰格式\n     * @type {string}\n     */\n    key: string;\n    /**\n     * @description 保持原始内容，不要翻译\n     * @type {string}\n     */\n    label: string;\n    /**\n     * @description 保持原始内容，不要翻译\n     * @type {string}\n     */\n    placeholder: string;\n  }[];\n  columns: {\n    slot: boolean;\n    /**\n     * @description 保持原始内容，不要翻译\n     * @type {string}\n     */\n    title: string;\n    /**\n     * @description 翻译成英文，驼峰格式\n     * @type {string}\n     */\n    dataIndex: string;\n    /**\n     * @description 翻译成英文，驼峰格式\n     * @type {string}\n     */\n    key: string;\n  }[];\n  pagination: {\n    show: boolean;\n    page: string;\n    size: string;\n    total: string;\n  };\n  includeModifyModal: boolean;\n  fetchName: string;\n  result: string;\n  serviceName: string;\n};\n"
  },
  {
    "path": "materials/blocks/测试使用 jsx 作为模版引擎/config/viewPrompt.ejs",
    "content": "<%- model %> 将这段 json 中，filters 字段中的 key\r\n字段的值翻译为英文，使用驼峰语法，label、placeholder 字段的值保留中文。columns 字段中的\r\nkey、dataIndex 字段的值翻译为英文，使用驼峰语法，title 字段的值保留中文。 返回翻译后的 markdown\r\n语法的代码块\r\n"
  },
  {
    "path": "materials/blocks/测试使用 jsx 作为模版引擎/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/blocks/测试使用 jsx 作为模版引擎/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/blocks/测试使用 jsx 作为模版引擎/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    try {\n      await main.handleAfterCompile();\n    } catch (ex) {\n      console.log(ex);\n    }\n  },\n  complete: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    try {\n      await main.handleComplete();\n    } catch (ex) {\n      console.log(ex);\n    }\n  },\n  initFiltersFromImage: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    const res = await main.handleInitFiltersFromImage();\n    return res;\n  },\n  initFiltersFromText: (lowcodeContext) => {\n    let filters = lowcodeContext.params\n      .replace(/\\r\\n/g, '\\n')\n      .replace(/\\r/g, '\\n')\n      .split('\\n');\n    filters = filters.map((item) => {\n      const s = item.replace(/：|：/g, ':').split(':');\n      return {\n        component: (s[1] || '').indexOf('选择') > -1 ? 'select' : 'input',\n        key: s[0].trim(),\n        label: s[0].trim(),\n        placeholder: s[1] || '',\n      };\n    });\n    lowcodeContext.outputChannel.appendLine(JSON.stringify(filters));\n    return { ...lowcodeContext.model, filters };\n  },\n  initColumnsFromImage: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    const res = await main.handleInitColumnsFromImage();\n    return res;\n  },\n  initColumnsFromText: (lowcodeContext) => {\n    let columns = lowcodeContext.params\n      .replace(/\\r\\n/g, '\\n')\n      .replace(/\\r/g, '\\n')\n      .split('\\n');\n    columns = columns.map((s) => ({\n      slot: false,\n      title: s,\n      dataIndex: s,\n      key: s,\n    }));\n    lowcodeContext.outputChannel.appendLine(JSON.stringify(columns));\n    return { ...lowcodeContext.model, columns };\n  },\n  askChatGPT: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    const res = await main.handleAskChatGPT();\n    return res;\n  },\n};\n"
  },
  {
    "path": "materials/blocks/测试使用 jsx 作为模版引擎/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { CompileContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/blocks/测试使用 jsx 作为模版引擎/script/src/main.ts",
    "content": "import * as path from 'path';\nimport { window, env, workspace } from 'vscode';\nimport * as fs from 'fs-extra';\nimport * as execa from 'execa';\nimport * as ejs from 'ejs';\nimport axios from 'axios';\nimport { lint } from '@share/utils/lint';\nimport { renderTemplates } from '@share/utils/tsx';\nimport { translate } from '@share/TypeChatSlim/index';\nimport { generalBasic } from '@share/BaiduOCR/index';\nimport { typescriptToMock } from '@share/utils/json';\nimport { context } from './context';\nimport { PageConfig } from '../../config/schema';\n\nexport async function handleInitFiltersFromImage() {\n  const { lowcodeContext } = context;\n  if (!lowcodeContext?.clipboardImage) {\n    window.showInformationMessage('剪贴板里没有截图');\n    return lowcodeContext?.model;\n  }\n  const ocrRes = await generalBasic({ image: lowcodeContext!.clipboardImage! });\n  env.clipboard.writeText(ocrRes.words_result.map((s) => s.words).join('\\r\\n'));\n  window.showInformationMessage('内容已经复制到剪贴板');\n  const filters = ocrRes.words_result\n    .map((s) => s.words)\n    .reduce((result, value, index, array) => {\n      if (index % 2 === 0) {\n        result.push(array.slice(index, index + 2));\n      }\n      return result;\n    }, [] as string[][]);\n  const formatedFilters = filters.map((s) => ({\n    component: s[1].indexOf('选择') > -1 ? 'select' : 'input',\n    key: s[0].replace(/:|：/g, '').trim(),\n    label: s[0].replace(/:|：/g, '').trim(),\n    placeholder: s[1],\n  }));\n  return { ...lowcodeContext.model, filters: formatedFilters };\n}\n\nexport async function handleInitColumnsFromImage() {\n  const { lowcodeContext } = context;\n  if (!lowcodeContext?.clipboardImage) {\n    window.showInformationMessage('剪贴板里没有截图');\n    return lowcodeContext?.model;\n  }\n  const ocrRes = await generalBasic({ image: lowcodeContext!.clipboardImage! });\n  env.clipboard.writeText(ocrRes.words_result.map((s) => s.words).join('\\r\\n'));\n  window.showInformationMessage('内容已经复制到剪贴板');\n  const columns = ocrRes.words_result.map((s) => ({\n    slot: false,\n    title: s.words,\n    dataIndex: s.words,\n    key: s.words,\n  }));\n  return { ...lowcodeContext.model, columns };\n}\n\nexport async function handleAskChatGPT() {\n  const { lowcodeContext } = context;\n  const schema = fs.readFileSync(\n    path.join(lowcodeContext!.materialPath, 'config/schema.ts'),\n    'utf8',\n  );\n  const typeName = 'PageConfig';\n  const res = await translate<PageConfig>({\n    schema,\n    typeName,\n    request: JSON.stringify(lowcodeContext!.model as PageConfig),\n    completePrompt:\n      `你是一个根据以下 TypeScript 类型定义将用户请求转换为 \"${typeName}\" 类型的 JSON 对象的服务，并且按照字段的注释进行处理:\\n` +\n      `\\`\\`\\`\\n${schema}\\`\\`\\`\\n` +\n      `以下是用户请求:\\n` +\n      `\"\"\"\\n${JSON.stringify(lowcodeContext!.model as PageConfig)}\\n\"\"\"\\n` +\n      `The following is the user request translated into a JSON object with 2 spaces of indentation and no properties with the value undefined:\\n`,\n    createChatCompletion: lowcodeContext!.createChatCompletion,\n    showWebview: true,\n    extendValidate: (jsonObject) => ({ success: true, data: jsonObject }),\n  });\n  lowcodeContext!.outputChannel.appendLine(JSON.stringify(res, null, 2));\n  if (res.success) {\n    return { ...res.data };\n  }\n  return lowcodeContext!.model;\n}\n\nexport async function handleAfterCompile() {\n  const { lowcodeContext } = context;\n  const tempWorkPath = path.join(\n    lowcodeContext?.env.privateMaterialsPath || '',\n    '.lowcode',\n  );\n  await renderTemplates(\n    {\n      ...lowcodeContext?.model,\n      title: '12121',\n    },\n    path.join(tempWorkPath, 'src'),\n  );\n}\n\nexport async function handleComplete() {\n  const { lowcodeContext } = context;\n  const createBlockPath = context.lowcodeContext?.createBlockPath;\n  if (createBlockPath) {\n    // #region lint\n    lint({\n      createBlockPath,\n      rootPath: lowcodeContext!.env.rootPath,\n    });\n    // #endregion\n\n    // #region 更新 mock 服务\n    const mockType = fs\n      .readFileSync(path.join(createBlockPath, 'temp.mock.type').toString())\n      .toString();\n    fs.removeSync(path.join(createBlockPath, 'temp.mock.type'));\n    const { mockCode, mockData } = typescriptToMock(mockType);\n    const mockTemplate = fs\n      .readFileSync(\n        path.join(createBlockPath, 'temp.mock.script.ejs').toString(),\n      )\n      .toString();\n    fs.removeSync(path.join(createBlockPath, 'temp.mock.script.ejs'));\n    // @ts-ignore\n    if (!lowcodeContext?.model.includeModifyModal) {\n      fs.removeSync(path.join(path.join(createBlockPath, 'ModifyModal')));\n    }\n    const mockScript = ejs.render(mockTemplate, {\n      ...lowcodeContext!.model,\n      mockCode,\n      mockData,\n      createBlockPath: createBlockPath.replace(':', ''),\n    });\n    const mockProjectPathRes = await axios\n      .get('http://localhost:3000/mockProjectPath', { timeout: 1000 })\n      .catch(() => {\n        // window.showInformationMessage(\n        //   '获取 mock 项目路径失败，跳过更新 mock 服务',\n        // );\n      });\n    if (mockProjectPathRes?.data.result) {\n      const projectName = workspace.rootPath\n        ?.replace(/\\\\/g, '/')\n        .split('/')\n        .pop();\n      const mockRouteFile = path.join(\n        mockProjectPathRes.data.result,\n        `${projectName}.js`,\n      );\n      let mockFileContent = `\n\t\t\timport KoaRouter from 'koa-router';\n\t\t\timport proxy from '../middleware/Proxy';\n\t\t\timport { delay } from '../lib/util';\n\n\t\t\tconst Mock = require('mockjs');\n\n\t\t\tconst { Random } = Mock;\n\n\t\t\tconst router = new KoaRouter();\n\t\t\trouter{{mockScript}}\n\t\t\tmodule.exports = router;\n\t\t\t`;\n\n      if (fs.existsSync(mockRouteFile)) {\n        mockFileContent = fs.readFileSync(mockRouteFile).toString().toString();\n        const index = mockFileContent.lastIndexOf(')') + 1;\n        mockFileContent = `${mockFileContent.substring(\n          0,\n          index,\n        )}{{mockScript}}\\n${mockFileContent.substring(index)}`;\n      }\n      mockFileContent = mockFileContent.replace(/{{mockScript}}/g, mockScript);\n      fs.writeFileSync(mockRouteFile, mockFileContent);\n      try {\n        execa.sync('node', [\n          path.join(\n            mockProjectPathRes.data.result\n              .replace(/\\\\/g, '/')\n              .replace('/src/routes', ''),\n            '/node_modules/eslint/bin/eslint.js',\n          ),\n          mockRouteFile,\n          '--resolve-plugins-relative-to',\n          mockProjectPathRes.data.result\n            .replace(/\\\\/g, '/')\n            .replace('/src/routes', ''),\n          '--fix',\n        ]);\n      } catch (err) {\n        console.log(err);\n      }\n      // #endregion\n    }\n  }\n}\n"
  },
  {
    "path": "materials/blocks/测试使用 jsx 作为模版引擎/src/ModifyModal/index.vue.ejs",
    "content": "<template>\n  <a-modal\n    :visible=\"props.visible\"\n    :title=\"props.title\"\n    :width=\"700\"\n    @ok=\"presenter.handleSubmit\"\n    @cancel=\"presenter.handleCancel\"\n    :ok-button-props=\"{ loading: model.loading.value }\"\n    :mask-closable=\"false\"\n  >\n    <a-form :label-col=\"{ span: 4 }\" :wrapper-col=\"{ span: 12 }\">\n\t\t\t<% modifyModal.formItems.map(item => { _%>\n\t\t\t\t<% if(item.component === \"input\") { _%>\n\t\t\t\t\t<a-form-item\n\t\t\t\t\t\t<% if(item.label) { _%>\n\t\t\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\tv-bind=\"presenter.validateInfos.<%= item.key %>\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<a-input \n\t\t\t\t\t\t\tv-model:value=\"model.formData.<%= item.key %>\" \n\t\t\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\t\t\tallow-clear\n\t\t\t\t\t\t\t<% if(item.maxlength) { _%>\n\t\t\t\t\t\t\t:maxlength=\"<%= item.maxlength %>\"\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t\t<% if(item.showCount) { _%>\n\t\t\t\t\t\t\tshowCount\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t>\n\t\t\t\t\t\t</a-input>\n\t\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item.component === \"input-password\") { _%>\n\t\t\t\t\t<a-form-item\n\t\t\t\t\t\t<% if(item.label) { _%>\n\t\t\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\tv-bind=\"presenter.validateInfos.<%= item.key %>\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<a-input-password\n\t\t\t\t\t\t\tv-model:value=\"model.formData.<%= item.key %>\" \n\t\t\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\t\t\tallowClear\n\t\t\t\t\t\t\t<% if(item.maxlength) { _%>\n\t\t\t\t\t\t\t:maxlength=\"<%= item.maxlength %>\"\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t\t<% if(item.showCount) { _%>\n\t\t\t\t\t\t\tshowCount\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t></a-input-password>\n\t\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item.component === \"input-number\") { _%>\n\t\t\t\t\t<a-form-item\n\t\t\t\t\t\t<% if(item.label) { _%>\n\t\t\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\tv-bind=\"presenter.validateInfos.<%= item.key %>\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<a-input-number\n\t\t\t\t\t\t\tv-model:value=\"model.formData.<%= item.key %>\"\n\t\t\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\t\t\tallowClear\n\t\t\t\t\t\t\t<% if(item.max) { _%>\n\t\t\t\t\t\t\t:max=\"<%= item.max %>\"\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t\t<% if(item.min) { _%>\n\t\t\t\t\t\t\t:min=\"<%= item.min %>\"\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t\t<% if(item.step) { _%>\n\t\t\t\t\t\t\t:step=\"<%= item.step %>\"\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t></a-input-number>\n\t\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item.component === \"textarea\") { _%>\n\t\t\t\t\t<a-form-item\n\t\t\t\t\t\t<% if(item.label) { _%>\n\t\t\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\tv-bind=\"presenter.validateInfos.<%= item.key %>\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<a-textarea\n\t\t\t\t\t\t\tv-model:value=\"model.formData.<%= item.key %>\" \n\t\t\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\t\t\tallow-clear\n\t\t\t\t\t\t\t<% if(item.maxlength) { _%>\n\t\t\t\t\t\t\t:maxlength=\"<%= item.maxlength %>\"\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t\t<% if(item.showCount) { _%>\n\t\t\t\t\t\t\tshowCount\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t>\n\t\t\t\t\t\t</a-textarea>\n\t\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item.component === \"select\") { _%>\n\t\t\t\t\t<a-form-item \n\t\t\t\t\t\t<% if(item.label) { _%>\n\t\t\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t\t\t<% } _%> \n\t\t\t\t\t\tv-bind=\"presenter.validateInfos.<%= item.key %>\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<a-select\n\t\t\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\t\t\tallow-clear\n\t\t\t\t\t\t\t:options=\"model.options.<%= item.key %>\"\n\t\t\t\t\t\t\tv-model:value=\"model.formData.<%= item.key %>\"\n\t\t\t\t\t\t\t<% if(item.labelInValue) { _%>\n\t\t\t\t\t\t\tlabelInValue\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t\t<% if(item.mode) { _%>\n\t\t\t\t\t\t\tmode=\"<%= item.mode %>\"\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t\toptionFilterProp=\"<%= item.optionFilterProp || 'label' %>\"\n\t\t\t\t\t\t\t<% if(item.showSearch) { _%>\n\t\t\t\t\t\t\tshowSearch\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t\t<% if(item.hideArrow) { _%>\n\t\t\t\t\t\t\t:showArrow=\"false\"\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t></a-select>\n\t\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item.component === \"radio-group\") { _%>\n\t\t\t\t\t<a-form-item \n\t\t\t\t\t\t<% if(item.label) { _%>\n\t\t\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\tv-bind=\"presenter.validateInfos.<%= item.key %>\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<a-radio-group v-model:value=\"model.formData.<%= item.key %>\">\n\t\t\t\t\t\t\t<a-radio\n\t\t\t\t\t\t\t\tv-for=\"item in model.options.<%= item.key %>\"\n\t\t\t\t\t\t\t\t:value=\"item.value\"\n\t\t\t\t\t\t\t\t:key=\"item.value\"\n\t\t\t\t\t\t\t\t>{{ item.label }}\n\t\t\t\t\t\t\t</a-radio>\n\t\t\t\t\t\t</a-radio-group>\n\t\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item.component === \"checkbox-group\") { _%>\n\t\t\t\t\t<a-form-item \n\t\t\t\t\t\t<% if(item.label) { _%>\n\t\t\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\tv-bind=\"presenter.validateInfos.<%= item.key %>\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<a-checkbox-group\n\t\t\t\t\t\t\tv-model:value=\"model.formData.<%= item.key %>\"\n\t\t\t\t\t\t\tstyle=\"width: 100%; margin-top: 6px\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<a-row>\n\t\t\t\t\t\t\t<a-col\n\t\t\t\t\t\t\t\t:span=\"8\"\n\t\t\t\t\t\t\t\tv-for=\"item in model.options.<%= item.key %>\"\n\t\t\t\t\t\t\t\t:key=\"item.value\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<a-checkbox :value=\"item.value\">{{ item.label }} </a-checkbox>\n\t\t\t\t\t\t\t</a-col>\n\t\t\t\t\t\t\t</a-row>\n\t\t\t\t\t\t</a-checkbox-group>\n\t\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item.component === \"switch\") { _%>\n\t\t\t\t\t<a-form-item \n\t\t\t\t\t\t<% if(item.label) { _%>\n\t\t\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t\t\t<% } _%> \n\t\t\t\t\t\tv-bind=\"presenter.validateInfos.<%= item.key %>\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<a-switch\n\t\t\t\t\t\t\tv-model:checked=\"model.formData.<%= item.key %>\"\n\t\t\t\t\t\t\t<% if(item.checkedChildren) { _%>\n\t\t\t\t\t\t\tcheckedChildren=\"<%= item.checkedChildren %>\"\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t\t<% if(item.unCheckedChildren) { _%>\n\t\t\t\t\t\t\tunCheckedChildren=\"<%= item.unCheckedChildren %>\"\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t\t<% if(item.checkedValue) { _%>\n\t\t\t\t\t\t\t\tcheckedValue=\"<%= item.checkedValue || 'true' %>\"\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t\t<% if(item.unCheckedValue) { _%>\n\t\t\t\t\t\t\t\tunCheckedValue=\"<%= item.unCheckedValue || 'false' %>\"\n\t\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\t></a-switch>\n\t\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item.component === \"date-picker\") { _%>\n\t\t\t\t\t<a-form-item \n\t\t\t\t\t\t<% if(item.label) { _%>\n\t\t\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t\t\t<% } _%> \n\t\t\t\t\t\tv-bind=\"presenter.validateInfos.<%= item.key %>\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<a-date-picker\n\t\t\t\t\t\t\tv-model:value=\"model.formData.<%= item.key %>\"\n\t\t\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\t\t\tallow-clear\n\t\t\t\t\t\t\tpicker=\"<%= item.picker || 'date' %>\"\n\t\t\t\t\t\t\t:showTime=\"<%= item.showTime || false %>\"\n\t\t\t\t\t\t\t:showNow=\"<%= item.showNow || false %>\"\n\t\t\t\t\t\t\t:showToday=\"<%= item.showToday || false %>\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item.component === \"range-picker\") { _%>\n\t\t\t\t\t<a-form-item \n\t\t\t\t\t\t<% if(item.label) { _%>\n\t\t\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t\t\t<% } _%> \n\t\t\t\t\t\tv-bind=\"presenter.validateInfos.<%= item.key %>\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<a-range-picker\n\t\t\t\t\t\t\tv-model:value=\"model.formData.<%= item.key %>\"\n\t\t\t\t\t\t\t:placeholder=\"[<%- item.placeholder || '\\'\\'' %>,<%- item.placeholder || '\\'\\'' %>]\"\n\t\t\t\t\t\t\tallow-clear\n\t\t\t\t\t\t\tpicker=\"<%= item.picker || 'date' %>\"\n\t\t\t\t\t\t\t:showTime=\"<%= item.showTime || false %>\"\n\t\t\t\t\t\t\t:showNow=\"<%= item.showNow || false %>\"\n\t\t\t\t\t\t\t:showToday=\"<%= item.showToday || false %>\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%>\n\t\t\t\t<% if(item.component === \"time-picker\") { _%>\n\t\t\t\t\t<a-form-item \n\t\t\t\t\t\t<% if(item.label) { _%>\n\t\t\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t\t\t<% } _%> \n\t\t\t\t\t\tv-bind=\"presenter.validateInfos.<%= item.key %>\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<a-time-picker\n\t\t\t\t\t\t\tv-model:value=\"model.formData.<%= item.key %>\"\n\t\t\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\t\t\tallow-clear\n\t\t\t\t\t\t/>\n\t\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%>\n\t\t\t<% }) _%>\n    </a-form>\n  </a-modal>\n</template>\n<script lang=\"ts\" setup>\nimport { usePresenter } from \"./presenter\";\n\ninterface IProps {\n  title: string\n  visible: boolean\n  action: 'add' | 'edit' | 'view'\n  id?: number\n}\n\ninterface IEmit {\n  (event: 'cancel'): void\n  (event: 'ok'): void\n}\n\nconst props = defineProps<IProps>()\n\nconst emit = defineEmits<IEmit>()\n\nconst presenter = usePresenter(props, emit);\nconst { model } = presenter;\n</script>\n"
  },
  {
    "path": "materials/blocks/测试使用 jsx 作为模版引擎/src/ModifyModal/model.ts.ejs",
    "content": "import { reactive, ref } from \"vue\";\n<% if(modifyModal.formItems.some(s => (s.type || \"\").indexOf(\"Dayjs\") > -1)) { _%>\nimport type { Dayjs } from \"dayjs\";\n<% } _%>\n\nexport interface IFormData {\n\tid?:number;\n\t<% modifyModal.formItems.map(item => { _%>\n\t\t<%= item.key %><% if(item.optional){ _%>?<% } _%>: <%= item.type %>;\n\t<% }) _%>\n}\n\nconst defaultFormData: IFormData = {\n\t<% modifyModal.formItems.map(item => { _%>\n\t\t<%= item.key %>: <%- item.defaultValue || '\\\"\\\"' %>,\n\t<% }) _%>\n};\n<% if(modifyModal.formItems.some(s => s.component === \"select\" || s.component === \"radio-group\" || s.component === \"checkbox-group\")){ %>\ninterface IOptionItem {\n  label: string;\n  value: string;\n}\n\ninterface IOptions {\n  <% modifyModal.formItems.filter(s => s.component === \"select\" || s.component === \"radio-group\" || s.component === \"checkbox-group\").map(item => { _%>\n\t\t<%= item.key %>: IOptionItem[];\n\t<% }) _%>\n}\n\nconst defaultOptions: IOptions = {\n  <% modifyModal.formItems.filter(s => s.component === \"select\" || s.component === \"radio-group\" || s.component === \"checkbox-group\").map(item => { _%>\n\t\t<%= item.key %>: [],\n\t<% }) _%>\n};\n<% } %>\n\nexport const useModel = () => {\n  const formData = reactive<IFormData>({ ...defaultFormData });\n\t<% if(modifyModal.formItems.some(s => s.component === \"select\" || s.component === \"radio-group\" || s.component === \"checkbox-group\")){ _%>\n  const options = reactive<IOptions>({ ...defaultOptions });\n\t<% } _%>\n  const loading = ref(false);\n\n  return { \n\t\tformData, \n\t\t<% if(modifyModal.formItems.some(s => s.component === \"select\" || s.component === \"radio-group\" || s.component === \"checkbox-group\")){ _%>\n\t\toptions,\n\t\t<% } _%>\n\t\tloading \n\t};\n};\n\nexport type Model = ReturnType<typeof useModel>;\n"
  },
  {
    "path": "materials/blocks/测试使用 jsx 作为模版引擎/src/ModifyModal/presenter.tsx.ejs",
    "content": "import Service from \"./service\";\nimport { useModel } from \"./model\";\nimport { Form, message } from \"ant-design-vue\";\nimport { watch, reactive } from \"vue\";\nimport { Rule } from 'ant-design-vue/es/form/interface'\n\ninterface IProps {\n  title: string\n  visible: boolean\n  action: 'add' | 'edit' | 'view'\n  id?: number\n}\n\ninterface IEmit {\n  (event: 'cancel'): void\n  (event: 'ok'): void\n}\n\nconst { useForm } = Form;\n\nexport const usePresenter = (props: IProps, emit: IEmit) => {\n  const model = useModel();\n  const service = new Service(model);\n\n  const rules: Record<string, Rule[]> = reactive({\n\t\t<% modifyModal.formItems.map(item => { _%>\n\t\t\t<%= item.key %>: [{ required: <%= item.required || false %>, message: \"<%= item.message %>\" }],\n\t\t<% }) _%>\n  });\n\n  const { resetFields, validate, validateInfos } = useForm(\n    model.formData,\n    rules,\n  );\n\n  watch(\n    () => props.visible,\n    () => {\n      if (props.visible && props.id) {\n        service.getDetail(props.id as number);\n      }\n    },\n  );\n\n  const handleSubmit = () => {\n    validate().then(() => {\n      if (props.action === \"add\") {\n        service.create().then(() => {\n          message.success(\"新建成功\");\n          resetFields();\n          emit(\"ok\");\n        });\n      } else {\n        service.edit().then(() => {\n          message.success(\"提交成功\");\n          resetFields();\n          emit(\"ok\");\n        });\n      }\n    });\n  };\n\n  const handleCancel = () => {\n    resetFields();\n    emit(\"cancel\");\n  };\n\n  return {\n    model,\n    service,\n    handleSubmit,\n    handleCancel,\n    validateInfos,\n  };\n};\n"
  },
  {
    "path": "materials/blocks/测试使用 jsx 作为模版引擎/src/ModifyModal/service.ts.ejs",
    "content": "import { Model } from \"./model\";\n\nexport default class Service {\n  private model: Model;\n\n  constructor(model: Model) {\n    this.model = model;\n  }\n\n  async getDetail(id: number) {\n    // const res = await fetchDetail({ id });\n    // this.model.formData.id = id;\n\t<% modifyModal.formItems.map(item => { _%>\n\t\t// this.model.formData.<%= item.key %> = res.result<%= item.key %>;\n\t<% }) _%>\n  }\n\n  async create() {\n    // this.model.loading.value = true;\n    // await create({\n\t<% modifyModal.formItems.map(item => { _%>\n\t\t// <%= item.key %>: this.model.formData.<%= item.key %>,\n\t<% }) _%>\n    // }).finally(() => {\n    //   this.model.loading.value = false;\n    // });\n  }\n\n  async edit() {\n    // this.model.loading.value = true;\n    // await edit(\n    //   { id: this.model.formData.id! },\n    //   {\n\t<% modifyModal.formItems.map(item => { _%>\n\t\t// <%= item.key %>: this.model.formData.<%= item.key %>,\n\t<% }) _%>\n    //   },\n    // ).finally(() => {\n    //   this.model.loading.value = false;\n    // });\n  }\n}\n"
  },
  {
    "path": "materials/blocks/测试使用 jsx 作为模版引擎/src/api.ts.ejs",
    "content": "import request from \"@/utils/request\";\n<% if (locals.api) { %>\n// #region <%= api.title %>\n<%= type %>\n\n<% if (api.req_query.length > 0 || api.req_params.length > 0 || api.query_path.params.length > 0) { _%>\nexport interface I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Params {\n\t<% api.req_query.filter(query => query.name !== pagination.page && query.name !== pagination.size).map(query => { _%>\n\t\t<%= query.name %>?: string;\n\t<% }) _%>\n\t<% api.req_params.filter(s => s.name !== pagination.page && s.name !== pagination.size).map(query => { _%>\n\t\t<%= query.name %>?: string;\n\t<% }) _%>\n\t<% api.query_path.params.filter(s => s.name !== pagination.page && s.name !== pagination.size).map(query => { _%>\n\t\t<%= query.name %>?: string;\n\t<% }) _%>\n\t<% if (pagination.show) { _%>\n\t\t<%= pagination.page %>: number;\n\t\t<%= pagination.size %>: number;\n\t<% } _%>\n}\n<% } %> \n<% if (requestBodyType && api.req_body_other.indexOf('{}') < 0) { %>\n    <%= requestBodyType %> \n<% } %> \n\n/**\n* <%= api.title %> \n* /project/<%= api.project_id %>/interface/api/<%= api._id %> \n* @author <%= api.username %>  \n* \n<% if (api.req_query.length > 0 || api.req_params.length > 0 || api.query_path.params.length > 0) { -%>* @param {I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Params} params<%- \"\\n\" %><% } _%>\n<% if (requestBodyType && api.req_body_other.indexOf('{}')<0) { -%>* @param {I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Data} data<%- \"\\n\" %><% } _%>\n* @returns\n*/\nexport function <%= funcName %> (\n<% if (api.req_query.length>0 || api.req_params.length > 0 || api.query_path.params.length > 0) { %>\nparams: I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Params,\n<% } _%> \n<% if (requestBodyType) { %> \ndata: I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Data\n<% } %> \n) {\nreturn request<<%= typeName %>[\"result\"]>({\n\t  url: `http://127.0.0.1:3000<%= api.query_path.path.replace(/\\{/g,\"${params.\") %>`, \n\t\tmethod: '<%= api.method %>',\n\t\t<% if(api.req_query.length>0 || api.req_params.length > 0) { %>params,<% } _%>\n        <% if (requestBodyType && api.req_body_other.indexOf('{}')<0) {%>data,<% } %> \n\t})\n}\n// #endregion\n<% } else { %>\n// #region\nexport interface I<%= fetchName.slice(0, 1).toUpperCase() + fetchName.slice(1) %>Result {\n  code: number;\n\tmsg: string;\n\t<% if (!pagination.show) { _%>\n\tresult: {\n\t\t<% columns.map((item, index) => { _%>\n\t\t\t<%= item.key || `column${index+1}` %>: string;\n\t\t<% }) _%>\n\t\t}[];\n\t<% } else { _%>\n\t\tresult: {\n\t\t\trecords: {\n\t\t\t\t<% columns.map((item, index) => { _%>\n\t\t\t\t\t<%= item.key || `column${index+1}` %>: string;\n\t\t\t\t<% }) _%>\n\t\t\t}[];\n\t\t\ttotal: number;\n\t\t}\n\t<% } _%>\n}\n\nexport interface I<%= fetchName.slice(0, 1).toUpperCase() + fetchName.slice(1) %>Params {\n\t<% filters.map(item => { _%>\n\t\t<%= item.key %>?: string;\n\t<% }) _%>\n\t<% if (pagination.show) { _%>\n\t\t<%= pagination.page %>: number;\n\t\t<%= pagination.size %>: number;\n\t<% } _%>\n}\n\nexport function <%= fetchName %>(\nparams: I<%= fetchName.slice(0, 1).toUpperCase() + fetchName.slice(1) %>Params\n) {\nreturn request<I<%= fetchName.slice(0, 1).toUpperCase() + fetchName.slice(1) %>Result[\"result\"]>({\n\turl: `http://127.0.0.1:3000/<%= createBlockPath %>/<%= fetchName %>`, \n\tmethod: 'GET',\n\tparams,\n});\n}\n// #endregion\n<% } %>"
  },
  {
    "path": "materials/blocks/测试使用 jsx 作为模版引擎/src/api.ts.template.tsx",
    "content": "import React from 'react';\n\ninterface IProps {\n  api?: {\n    title: string;\n    req_query: { name: string }[];\n    req_params: { name: string }[];\n    query_path: { params: { name: string }[] };\n    req_body_other: string;\n  };\n  requestBodyType: string;\n  type: string;\n  funcName: string;\n  fetchName: string;\n  title: string;\n  columns: { title: string; key: string }[];\n  filters: { key: string; label: string; component: string }[];\n  result: string;\n  pagination: { show: boolean; page: string; size: string };\n}\n\nconst Content: React.FC<IProps> = (props) => (\n  <>\n    {`import request from \"@/utils/request\";`}\n    {props.api && (\n      <>\n        // #region {props.api.title}\n        {props.type}\n        {(props.api.req_query.length > 0 ||\n          props.api.req_params.length > 0 ||\n          props.api.query_path.params.length > 0) && (\n          <>\n            {`export interface I${props.funcName\n              .slice(0, 1)\n              .toUpperCase()}${props.funcName.slice(1)}Params {`}\n            <>\n              {props.api.req_query\n                .filter(\n                  (query) =>\n                    query.name !== props.pagination.page &&\n                    query.name !== props.pagination.size,\n                )\n                .map((query) => (\n                  <>{query.name}?: string;</>\n                ))}\n              {props.api.req_params\n                .filter(\n                  (query) =>\n                    query.name !== props.pagination.page &&\n                    query.name !== props.pagination.size,\n                )\n                .map((query) => (\n                  <>{query.name}?: string;</>\n                ))}\n              {props.api.query_path.params\n                .filter(\n                  (query) =>\n                    query.name !== props.pagination.page &&\n                    query.name !== props.pagination.size,\n                )\n                .map((query) => (\n                  <>{query.name}?: string;</>\n                ))}\n              {props.pagination.show && (\n                <>\n                  {props.pagination.page}: number;\n                  {props.pagination.size}: number;\n                </>\n              )}\n            </>\n            {`}`}\n          </>\n        )}\n        {props.requestBodyType &&\n          props.api.req_body_other.indexOf('{}') < 0 && (\n            <>{props.requestBodyType}</>\n          )}\n        // #endregion\n      </>\n    )}\n  </>\n);\n\nexport default Content;\n"
  },
  {
    "path": "materials/blocks/测试使用 jsx 作为模版引擎/src/index.vue.ejs",
    "content": "<template>\n  <a-row :gutter=\"30\">\n    <% filters.map(item => { _%> \n\t\t  <a-col :xs=\"24\" :sm=\"24\" :md=\"12\" :lg=\"12\" :xl=\"8\" :xxl=\"6\">\n\t\t\t\t<% if(item.component === \"select\") { %>\n\t\t\t\t<a-form-item label=\"<%= item.label %>\">\n\t\t\t\t\t<a-select\n\t\t\t\t\t\tv-model:value=\"model.filterForm.<%= item.key %>\"\n\t\t\t\t\t\t:options=\"model.options.<%= item.key %>\"\n\t\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\t\tallow-clear\n\t\t\t\t\t></a-select>\n\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%> \n\t\t\t\t<% if(item.component === \"input\") { _%>\n\t\t\t\t<a-form-item label=\"<%= item.label %>\">\n\t\t\t\t\t<a-input\n\t\t\t\t\t\tv-model:value=\"model.filterForm.<%= item.key %>\"\n\t\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\t\tallow-clear\n\t\t\t\t\t></a-input>\n\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%> \n\t\t\t\t<% if(item.component === \"range-picker\") { _%>\n\t\t\t\t<a-form-item label=\"<%= item.label %>\">\n\t\t\t\t\t<a-range-picker\n\t\t\t\t\t\tv-model:value=\"model.filterForm.<%= item.key %>\"\n\t\t\t\t\t\tvalueFormat=\"YYYY-MM-DD\"\n\t\t\t\t\t\t:allowClear=\"false\"\n\t\t\t\t\t/>\n\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%> \n\t\t\t</a-col>\n\t\t<% }) _%>\n\t\t<a-col style=\"text-align: right; flex: 1\">\n\t\t\t<a-space>\n\t\t\t\t<a-button @click=\"presenter.handleClear\">重置</a-button>\n        <a-button @click=\"presenter.handleSearch\" type=\"primary\">查询</a-button>\n        <a-button @click=\"presenter.handleCreate\" type=\"primary\">\n          <template #icon><PlusOutlined /></template>\n          新增\n        </a-button>\n\t\t\t</a-space>\n\t\t</a-col>\n  </a-row>\n  <a-table\n    :loading=\"model.loading.list\"\n    :columns=\"columns\"\n    :data-source=\"model.tableList.value\"\n    :pagination=\"false\"\n  >\n\t<% columns.filter(item => item.slot).map((item, index) => { _%>\n\t\t<template #<%= item.key %>=\"{ record }\">\n\t\t\t{{ record.<%= item.key %> }}\n\t\t</template>\n\t\t<% }) _%>\n\t\t<template #operation=\"{ record }\">\n\t\t\t<a-space :size=\"0\">\n\t\t\t\t<% if(includeModifyModal) { _%>\n\t\t\t\t<a-button\n\t\t\t\t\ttype=\"link\"\n\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t@click=\"\n\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\tpresenter.handleView(record);\n\t\t\t\t\t\t}\n\t\t\t\t\t\"\n\t\t\t\t>\n\t\t\t\t\t查看\n\t\t\t\t</a-button>\n\t\t\t\t<% } _%>\n\t\t\t\t<a-button\n\t\t\t\t\ttype=\"link\"\n\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t@click=\"\n\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\tpresenter.handleEdit(record);\n\t\t\t\t\t\t}\n\t\t\t\t\t\"\n\t\t\t\t>\n\t\t\t\t\t编辑\n\t\t\t\t</a-button>\n\t\t\t\t<a-button\n\t\t\t\t\ttype=\"link\"\n\t\t\t\t\tdanger\n\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t@click=\"\n\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\tpresenter.handleDel(record);\n\t\t\t\t\t\t}\n\t\t\t\t\t\"\n\t\t\t\t>\n\t\t\t\t\t删除\n\t\t\t\t</a-button>\n\t\t\t</a-space>\n\t\t</template>\n  </a-table>\n  <% if(pagination.show) { _%>\n  <a-pagination\n    style=\"margin-top: 10px\"\n    @change=\"presenter.handlePageChange\"\n\t\t@showSizeChange=\"presenter.handlePageChange\"\n    v-model:current=\"model.pagination.page\"\n    :total=\"model.pagination.total\"\n    show-size-changer\n    show-quick-jumper\n  ></a-pagination>\n  <% } _%> <% if(includeModifyModal) { _%>\n  <ModifyModal\n    :id=\"model.modalInfo.id\"\n    :title=\"model.modalInfo.title\"\n    :visible=\"model.modalInfo.visible\"\n    :action=\"model.modalInfo.action\"\n    @ok=\"presenter.handleModalOk\"\n    @cancel=\"presenter.handleModalCancel\"\n  ></ModifyModal>\n  <% } _%>\n</template>\n<script lang=\"ts\" setup>\n  import { PlusOutlined } from \"@ant-design/icons-vue\";\n  <% if(includeModifyModal) { _%>\n  import ModifyModal from \"./ModifyModal/index.vue\";\n  <% } _%>\n  import { usePresenter } from \"./presenter\";\n\n  const presenter = usePresenter();\n  const { model } = presenter;\n\n  const columns = [\n    <% columns.map((item, index) => { _%>\n  \t\t{\n        title: \"<%= item.title || `column${index+1}` %>\",\n  \t\t\tdataIndex: \"<%= item.dataIndex || `column${index+1}` %>\",\n  \t\t\tkey: \"<%= item.key || `column${index+1}` %>\",\n  \t\t\t<% if(item.width) {%>width: \"<%= item.width %>\",<% } _%>\n\t\t\t\t<% if(item.slot) {%>slots: { customRender: \"<%= item.key %>\"},<% } _%>\n  \t\t},\n  \t<% }) _%>\n  \t{\n      title: \"操作\",\n      key: \"operation\",\n  \t\twidth: 100,\n\t\t\tslots:{customRender: \"operation\"}\n    }\n  ];\n</script>\n"
  },
  {
    "path": "materials/blocks/测试使用 jsx 作为模版引擎/src/model.ts.template.tsx",
    "content": "import React from 'react';\n\ninterface IProps {\n  api?: object;\n  funcName: string;\n  fetchName: string;\n  title: string;\n  columns: { title: string; key: string }[];\n  filters: { key: string; label: string; component: string }[];\n  result: string;\n  pagination: { show: boolean };\n}\n\nconst Content: React.FC<IProps> = (props) => (\n  <>\n    {`import { reactive, ref } from \"vue\";`}\n    {props.api &&\n      `import { I${\n        props.funcName.slice(0, 1).toUpperCase() + props.funcName.slice(1)\n      }Result } from \"./api\";`}\n    {!props.api &&\n      `import { I${\n        props.fetchName.slice(0, 1).toUpperCase() + props.fetchName.slice(1)\n      }Result } from \"./api\";`}\n    {!props.api && (\n      <>\n        {`interface ITableListItem {`}\n        <>\n          {props.columns.map((item, index) => (\n            <>\n              {`/** \n\t\t\t\t\t\t\t* ${item.title}\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t`}\n              {item.key || `column${index + 1}`}: string;\n            </>\n          ))}\n          <>\n            <>\n              {`\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * 接口返回的数据，新增字段不需要改 ITableListItem 直接从这里取\n\t\t\t\t\t\t */\n\t\t\t\t\t\t`}\n              {`apiResult: I${props.fetchName\n                .slice(0, 1)\n                .toUpperCase()}${props.fetchName.slice(1)}Result${\n                props.result\n              }[0]`}\n            </>\n          </>\n        </>\n        {`}`}\n      </>\n    )}\n    {`interface IFormData {`}\n    <>\n      {props.filters.map((item) => (\n        <>\n          {`/**\n\t\t\t\t\t* ${item.label}\n\t\t\t\t\t*/\n\t\t\t\t`}\n          {item.component === 'range-picker' && `${item.key}?: string[];`}\n          {item.component !== 'range-picker' && `${item.key}?: string;`}\n        </>\n      ))}\n    </>\n    {`}`}\n    {props.filters.some((s) => s.component === 'select') && (\n      <>\n        {`interface IOptionItem {\n\t\t\t\t\t\tlabel: string;\n\t\t\t\t\t\tvalue: string;\n\t\t\t\t\t}`}\n        {`interface IOptions {`}\n        <>\n          {props.filters\n            .filter((s) => s.component === 'select')\n            .map((item) => (\n              <>{`${item.key}: IOptionItem[],`}</>\n            ))}\n        </>\n        {`}`}\n        {`const defaultOptions: IOptions = {`}\n        <>\n          {props.filters\n            .filter((s) => s.component === 'select')\n            .map((item) => (\n              <>{`${item.key}: [],`}</>\n            ))}\n        </>\n        {`};`}\n      </>\n    )}\n    {`;export const defaultFormData: IFormData = {`}\n    <>\n      {props.filters.map((item) => (\n        <>{`${item.key}: undefined,`}</>\n      ))}\n    </>\n    {`}`}\n    {`;export const useModel = () => {`}\n    <>\n      <>\n        {`const filterForm = reactive<IFormData>({ ...defaultFormData });`}\n        {props.filters.some((s) => s.component === 'select') && (\n          <>{`const options = reactive<IOptions>({ ...defaultOptions });`}</>\n        )}\n        {props.api && (\n          <>\n            {`\n\t\t\t\t\t\t\tconst tableList = ref<(I${props.funcName\n                .slice(0, 1)\n                .toUpperCase()}${props.funcName.slice(1)}Result${\n                props.result\n              }[0] & { _?: unknown })[]>(\n\t\t\t\t\t\t\t\t[],\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t`}\n          </>\n        )}\n        {!props.api && (\n          <>\n            {`\n\t\t\t\t\t\t\tconst tableList = ref<(ITableListItem & { _?: unknown })[]>(\n\t\t\t\t\t\t\t\t[],\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t`}\n          </>\n        )}\n        {props.pagination.show && (\n          <>\n            {`\n\t\t\t\t\t\t\tconst pagination = reactive<{\n\t\t\t\t\t\t\t\tpage: number;\n\t\t\t\t\t\t\t\tpageSize: number;\n\t\t\t\t\t\t\t\ttotal: number;\n\t\t\t\t\t\t\t}>({\n\t\t\t\t\t\t\t\tpage: 1,\n\t\t\t\t\t\t\t\tpageSize: 10,\n\t\t\t\t\t\t\t\ttotal: 0,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t`}\n          </>\n        )}\n        {`\n\t\t\t\t\tconst loading = reactive<{ list: boolean }>({\n\t\t\t\t\t\tlist: false,\n\t\t\t\t\t});\n\t\t\t\t`}\n        {`return {`}\n        <>\n          filterForm,\n          {props.filters.some((s) => s.component === 'select') && `options,`}\n          tableList,\n          {props.pagination.show && `pagination,`}\n          loading,\n        </>\n        {`}`}\n      </>\n    </>\n    {`};`}\n    {`export type Model = ReturnType <typeof useModel>;`}\n  </>\n);\n\nexport default Content;\n"
  },
  {
    "path": "materials/blocks/测试使用 jsx 作为模版引擎/src/presenter.tsx.ejs",
    "content": "import Service from \"./service\";\nimport { defaultFormData, useModel } from \"./model\";\nimport { createVNode, onMounted } from \"vue\";\nimport { message, Modal } from \"ant-design-vue\";\nimport { ExclamationCircleOutlined } from \"@ant-design/icons-vue\";\n\nexport const usePresenter = () => {\n  const model = useModel();\n  const service = new Service(model);\n\n  onMounted(() => {\n    service.<%= serviceName %>();\n  });\n\n  const handleClear = () => {\n\t\tObject.assign(model.filterForm, defaultFormData)\n\t\t<% if(pagination.show) { _%>\n\t\t\tmodel.pagination.page = 1;\n\t\t<% } _%>\n    service.<%= serviceName %>();\n  };\n\n  const handleSearch = () => {\n\t\t<% if(pagination.show) { _%>\n\t\t\tmodel.pagination.page = 1;\n\t\t<% } _%>\n    service.<%= serviceName %>();\n  };\n\n  <% if(pagination.show) { _%>\n  const handlePageChange = (page: number, pageSize: number) => {\n    if (pageSize !== model.pagination.pageSize) {\n      model.pagination.pageSize = pageSize;\n      model.pagination.page = 1;\n    } else {\n      model.pagination.page = page;\n    }\n    service.<%= serviceName %>();\n  };\n  <% } _%>\n\n  const handleDel = (record: typeof model.tableList.value[0]) => {\n    Modal.confirm({\n      title: \"此操作将删除该选项，是否继续？\",\n      icon: createVNode(ExclamationCircleOutlined),\n\t\t\tokText: \"确定\",\n      cancelText: \"取消\",\n      onOk() {\n        message.success(\"删除成功\");\n      },\n    });\n  };\n\n  const handleCreate = () => {\n\t<% if(includeModifyModal) { _%>\n    model.modalInfo.visible = true;\n    model.modalInfo.title = \"新建\";\n    model.modalInfo.action = \"add\";\n    model.modalInfo.id = undefined;\n\t<% } _%>\n  };\n\n  const handleEdit = (record: typeof model.tableList.value[0]) => {\n\t<% if(includeModifyModal) { _%>\n    model.modalInfo.visible = true;\n    model.modalInfo.title = \"编辑\";\n    model.modalInfo.action = \"edit\";\n    model.modalInfo.id = record.id;\n\t<% } _%>\n  };\n\n  <% if(includeModifyModal) { _%>\n  const handleView = (record: typeof model.tableList.value[0]) => {\n    model.modalInfo.visible = true;\n    model.modalInfo.title = \"查看\";\n    model.modalInfo.action = \"view\";\n    model.modalInfo.id = record.id;\n  };\n\n  const handleModalOk = () => {\n    model.modalInfo.visible = false;\n    service.<%= serviceName %>();\n  };\n\n  const handleModalCancel = () => {\n    model.modalInfo.visible = false;\n  };\n  <% } _%>\n\n  return {\n    model,\n    service,\n    handleClear,\n    handleSearch,\n\t<% if(pagination.show) { _%>\n\thandlePageChange,\n    <% } _%>\n\thandleDel,\n\thandleCreate,\n    handleEdit,\n\t<% if(includeModifyModal) { _%>\n\thandleView,\n\thandleModalOk,\n\thandleModalCancel\n\t<% } _%>\n  };\n};\n"
  },
  {
    "path": "materials/blocks/测试使用 jsx 作为模版引擎/src/service.ts.ejs",
    "content": "import { <%= locals.api ? funcName : fetchName %> } from \"./api\";\nimport { Model } from \"./model\"; \n\nexport default class Service {\n  private model: Model;\n\n  constructor(model: Model) {\n    this.model = model;\n  }\n\n  async <%= serviceName %>() {\n    this.model.loading.list = true;\n    const res = await <%= locals.api ? funcName : fetchName %>({\n\t\t\t<% filters.map(item => { _%>\n\t\t\t\t<%= item.key %>: this.model.filterForm.<%= item.key %>,\n\t\t\t<% }) _%>\n\t\t\t<% if(pagination.show) { _%>\n\t\t\t\t<%= pagination.page %>: this.model.pagination.page,\n\t\t\t\t<%= pagination.size %>: this.model.pagination.pageSize,\n\t\t\t<% } _%>\n\t\t}).finally(() => {\n\t\t\tthis.model.loading.list = false;\n\t\t});\n    this.model.tableList.value = res<%- result %>.map((s) => {\n      return {\n\t\t...s,\n\t\t<% columns.map((item, index) => { _%>\n\t\t\t<%= item.key || `column${index+1}` %>: s.<%= item.key || `column${index+1}` %>,\n\t\t<% }) _%>\n\t\tapiResult: s\n      };\n    });\n\t<% if(pagination.show) { _%>\n\tthis.model.pagination.total = res.<%- pagination.total %>;\n\t<% } _%>\n  }\n}\n"
  },
  {
    "path": "materials/blocks/测试使用 jsx 作为模版引擎/src/temp.mock.script.ejs",
    "content": ".get(`<%= createBlockPath %>/<%= fetchName %>`, async (ctx, next) => { <%- mockCode %> ctx.body = <%- mockData %>\n})\n"
  },
  {
    "path": "materials/blocks/测试使用 jsx 作为模版引擎/src/temp.mock.type.ejs",
    "content": "{\n  code: number;\n\tmsg: string;\n\t<% if (!pagination.show) { _%>\n\tresult: {\n\t\t<% columns.map((item, index) => { _%>\n\t\t\t<%= item.key || `column${index+1}` %>: string;\n\t\t<% }) _%>\n\t}[];\n\t<% } else { _%>\n\t\tresult: {\n\t\t\trecords: {\n\t\t\t\t<% columns.map((item, index) => { _%>\n\t\t\t\t\t<%= item.key || `column${index+1}` %>: string;\n\t\t\t\t<% }) _%>\n\t\t\t}[];\n\t\t\ttotal: number;\n\t\t}\n\t<% } _%>\n}"
  },
  {
    "path": "materials/blocks/测试脚本/config/model.json",
    "content": "{\n  \"name\": \"lowcode\"\n}"
  },
  {
    "path": "materials/blocks/测试脚本/config/preview.json",
    "content": "{\n\t\"title\": \"测试脚本\",\n\t\"description\": \"测试脚本\",\n\t\"img\": [\n\t\t\"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n\t],\n\t\"category\": [],\n\t\"schema\": \"amis\",\n\t\"scripts\": [\n\t\t{\n\t\t\t\"method\": \"intFromOcrText\",\n\t\t\t\"remark\": \"使用 ocr 结果初始化表单\"\n\t\t},\n\t\t{\n\t\t\t\"method\": \"askChatGPT\",\n\t\t\t\"remark\": \"askChatGPT\"\n\t\t}\n\t]\n}"
  },
  {
    "path": "materials/blocks/测试脚本/config/schema.json",
    "content": "{\n  \"formSchema\": {\n    \"schema\": {\n      \"type\": \"page\",\n      \"body\": [\n        {\n          \"type\": \"form\",\n          \"title\": \"\",\n          \"body\": [\n            {\n              \"type\": \"input-text\",\n              \"name\": \"name\",\n              \"label\": \"测试表单\",\n              \"id\": \"u:4886baa626cf\",\n              \"value\": \"\"\n            }\n          ],\n          \"id\": \"u:67967afb0e69\",\n          \"submitText\": \"\"\n        }\n      ],\n      \"id\": \"u:d87dbf6bf8df\",\n      \"asideResizor\": false,\n      \"style\": {\n        \"boxShadow\": \" 0px 0px 0px 0px transparent\"\n      },\n      \"pullRefresh\": {\n        \"disabled\": true\n      },\n      \"regions\": [\n        \"body\"\n      ]\n    },\n    \"conditionFiles\": {\n      \"name\": {\n        \"value\": \"123\",\n        \"exclude\": [\n          \"当表单name的值为123,删除这个数组里的文件.ejs\"\n        ]\n      }\n    },\n    \"excludeCompile\": [\n      \"不需要编译的文件,不会被删除.ejs\"\n    ]\n  }\n}"
  },
  {
    "path": "materials/blocks/测试脚本/config/viewPrompt.ejs",
    "content": "<%- model %> \r\n将这段 json 中，中文 key 翻译为英文，使用驼峰语法，\r\n返回翻译后的markdown语法的代码块"
  },
  {
    "path": "materials/blocks/测试脚本/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/blocks/测试脚本/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/blocks/测试脚本/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (context) => {\n    const compileHandler =\n      new main.CompileHandler3c5a281f3af548fda73cb864dd8f452b(context);\n    compileHandler.log('compile start');\n  },\n  afterCompile: (context) => {\n    const compileHandler =\n      new main.CompileHandler3c5a281f3af548fda73cb864dd8f452b(context);\n    compileHandler.log('compile end');\n  },\n  complete: (context) => {\n    const compileHandler =\n      new main.CompileHandler3c5a281f3af548fda73cb864dd8f452b(context);\n    compileHandler.log('compile complete');\n  },\n  intFromOcrText: (context) => {\n    const viewCallHandler =\n      new main.ViewCallHandler3c5a281f3af548fda73cb864dd8f452b(context);\n    viewCallHandler.log('call method intFromOcrText');\n    viewCallHandler.showInformationMessage('lowcode');\n    return viewCallHandler.intFromOcrText();\n  },\n  askChatGPT: (context) => {\n    const viewCallHandler =\n      new main.ViewCallHandler3c5a281f3af548fda73cb864dd8f452b(context);\n    viewCallHandler.log('call method askChatGPT');\n    return viewCallHandler.askChatGPT();\n  },\n};\n"
  },
  {
    "path": "materials/blocks/测试脚本/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { CompileContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/blocks/测试脚本/script/src/main.ts",
    "content": "import { CompileContext, ViewCallContext } from 'lowcode-context';\n\nexport class CompileHandler3c5a281f3af548fda73cb864dd8f452b {\n  private context!: CompileContext;\n\n  constructor(context: CompileContext) {\n    this.context = context;\n  }\n\n  log(value: string) {\n    this.context.outputChannel.appendLine(value);\n  }\n}\n\nexport class ViewCallHandler3c5a281f3af548fda73cb864dd8f452b {\n  private context!: ViewCallContext;\n\n  constructor(context: ViewCallContext) {\n    this.context = context;\n  }\n\n  log(value: string) {\n    this.context.outputChannel.appendLine(value);\n  }\n\n  showInformationMessage(msg: string) {\n    this.context.vscode.window.showInformationMessage(msg);\n  }\n\n  intFromOcrText() {\n    return Promise.resolve({ ...this.context.model, name: '测试一下' });\n  }\n\n  async askChatGPT() {\n    const res = await this.context.createChatCompletion({\n      messages: [{ role: 'user', content: this.context.params }],\n      handleChunk: (data) => {\n        this.context.outputChannel.append(data.text || '');\n      },\n    });\n    return { ...this.context.model, name: res };\n  }\n}\n"
  },
  {
    "path": "materials/blocks/测试脚本/src/README.md",
    "content": "在当前文件夹下放区块模板，并将此文件删除"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Descriptions 描述列表/config/model.json",
    "content": "{\n\t\"items\": [],\n\t\"bordered\": false,\n\t\"extra\": false,\n\t\"layout\": \"horizontal\",\n\t\"variableName\": \"\",\n\t\"title\": \"\",\n\t\"column\": \"\"\n}"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Descriptions 描述列表/config/preview.json",
    "content": "{\n\t\"title\": \"\",\n\t\"description\": \"\",\n\t\"img\": [\n\t\t\"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n\t],\n\t\"category\": [],\n\t\"schema\": \"amis\",\n\t\"scripts\": [\n\t\t{\n\t\t\t\"method\": \"OCR\",\n\t\t\t\"remark\": \"OCR 识别剪贴版截图\"\n\t\t},\n\t\t{\n\t\t\t\"method\": \"initFromOcrText\",\n\t\t\t\"remark\": \"初始化列表，参数中粘贴 ocr 识别出的结果，每一行表示一项，也可以手动输入\"\n\t\t},\n\t\t{\n\t\t\t\"method\": \"askChatGPT\",\n\t\t\t\"remark\": \"使用 ChatGPT 翻译模版数据里的 items.key 字段\"\n\t\t},\n\t\t{\n\t\t\t\"method\": \"intFromClipboardImage\",\n\t\t\t\"remark\": \"读取剪贴板截图并翻译，初始化列表\"\n\t\t}\n\t]\n}"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Descriptions 描述列表/config/schema.json",
    "content": "{\n\t\"formSchema\": {\n\t\t\"schema\": {\n\t\t\t\"type\": \"page\",\n\t\t\t\"body\": [\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"form\",\n\t\t\t\t\t\"title\": \"\",\n\t\t\t\t\t\"body\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"id\": \"u:11b127c5df46\",\n\t\t\t\t\t\t\t\"label\": \"变量名\",\n\t\t\t\t\t\t\t\"name\": \"variableName\",\n\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"id\": \"u:1fdc2ed6321c\",\n\t\t\t\t\t\t\t\"label\": \"title\",\n\t\t\t\t\t\t\t\"name\": \"title\",\n\t\t\t\t\t\t\t\"description\": \"标题\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\"id\": \"u:9cc79716dde1\",\n\t\t\t\t\t\t\t\"label\": \"bordered\",\n\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\"name\": \"bordered\",\n\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\"description\": \"是否展示边框\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"id\": \"u:43fbc9d670c3\",\n\t\t\t\t\t\t\t\"label\": \"column\",\n\t\t\t\t\t\t\t\"name\": \"column\",\n\t\t\t\t\t\t\t\"description\": \"一行的 DescriptionItems 数量，可以写成像素值或支持响应式的对象写法 { xs: 8, sm: 16, md: 24}，默认3\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\"id\": \"u:b8b2cb8217d1\",\n\t\t\t\t\t\t\t\"label\": \"extra\",\n\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\"name\": \"extra\",\n\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\"description\": \"描述列表的操作区域，显示在右上方\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\"id\": \"u:a8859cde1998\",\n\t\t\t\t\t\t\t\"label\": \"layout\",\n\t\t\t\t\t\t\t\"name\": \"layout\",\n\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"label\": \"horizontal\",\n\t\t\t\t\t\t\t\t\t\"value\": \"horizontal\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"label\": \"vertical\",\n\t\t\t\t\t\t\t\t\t\"value\": \"vertical\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\"description\": \"描述布局\",\n\t\t\t\t\t\t\t\"value\": \"horizontal\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"combo\",\n\t\t\t\t\t\t\t\"label\": \"描述列表\",\n\t\t\t\t\t\t\t\"name\": \"items\",\n\t\t\t\t\t\t\t\"multiple\": true,\n\t\t\t\t\t\t\t\"addable\": true,\n\t\t\t\t\t\t\t\"removable\": true,\n\t\t\t\t\t\t\t\"removableMode\": \"icon\",\n\t\t\t\t\t\t\t\"addBtn\": {\n\t\t\t\t\t\t\t\t\"label\": \"新增\",\n\t\t\t\t\t\t\t\t\"icon\": \"fa fa-plus\",\n\t\t\t\t\t\t\t\t\"level\": \"primary\",\n\t\t\t\t\t\t\t\t\"size\": \"sm\",\n\t\t\t\t\t\t\t\t\"id\": \"u:47ecb9e15ff1\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"items\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"key\",\n\t\t\t\t\t\t\t\t\t\"placeholder\": \"字段名\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:25b0c7b5e5a0\",\n\t\t\t\t\t\t\t\t\t\"label\": \"字段名（key）\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"label\",\n\t\t\t\t\t\t\t\t\t\"name\": \"label\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:6496cac4f4b8\",\n\t\t\t\t\t\t\t\t\t\"description\": \"内容的描述\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-number\",\n\t\t\t\t\t\t\t\t\t\"label\": \"span\",\n\t\t\t\t\t\t\t\t\t\"name\": \"span\",\n\t\t\t\t\t\t\t\t\t\"keyboard\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:9ee4d10df24a\",\n\t\t\t\t\t\t\t\t\t\"step\": 1,\n\t\t\t\t\t\t\t\t\t\"min\": 1,\n\t\t\t\t\t\t\t\t\t\"description\": \"包含列的数量\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"id\": \"u:186f183e9320\",\n\t\t\t\t\t\t\t\"strictMode\": false,\n\t\t\t\t\t\t\t\"syncFields\": [],\n\t\t\t\t\t\t\t\"tabsMode\": false,\n\t\t\t\t\t\t\t\"draggable\": true,\n\t\t\t\t\t\t\t\"draggableTip\": \"可拖动排序\",\n\t\t\t\t\t\t\t\"tabsStyle\": \"line\",\n\t\t\t\t\t\t\t\"tabsLabelTpl\": \"表单项${index+1}\",\n\t\t\t\t\t\t\t\"multiLine\": true,\n\t\t\t\t\t\t\t\"value\": [\n\t\t\t\t\t\t\t\t{}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\t\"submitText\": \"\",\n\t\t\t\t\t\"id\": \"u:67967afb0e69\"\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"pullRefresh\": {\n\t\t\t\t\"disabled\": true\n\t\t\t},\n\t\t\t\"regions\": [\n\t\t\t\t\"body\"\n\t\t\t],\n\t\t\t\"style\": {\n\t\t\t\t\"boxShadow\": \" 0px 0px 0px 0px transparent\"\n\t\t\t},\n\t\t\t\"asideResizor\": false,\n\t\t\t\"id\": \"u:d87dbf6bf8df\"\n\t\t},\n\t\t\"conditionFiles\": {\n\t\t\t\"name\": {\n\t\t\t\t\"value\": \"123\",\n\t\t\t\t\"exclude\": [\n\t\t\t\t\t\"当表单name的值为123,删除这个数组里的文件.ejs\"\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"excludeCompile\": [\n\t\t\t\"temp.mock.script.ejs\"\n\t\t]\n\t}\n}"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Descriptions 描述列表/config/schema.ts",
    "content": "export type IItems = {\n  /**\n   * @description 保持原始内容，不需要处理，不要翻译\n   * @type {string}\n   */\n  label: string;\n  /**\n   * @description 翻译成英文，驼峰格式\n   * @type {string}\n   */\n  key: string;\n  span?: number;\n}[];\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Descriptions 描述列表/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/blocks/现有模块中添加 antdv Descriptions 描述列表/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/blocks/现有模块中添加 antdv Descriptions 描述列表/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: (lowcodeContext) => {},\n  complete: (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    main.handleComplete();\n  },\n  initFromOcrText: (lowcodeContext) => {\n    let items = lowcodeContext.params\n      .replace(/\\r\\n/g, '\\n')\n      .replace(/\\r/g, '\\n')\n      .split('\\n');\n    items = items.map((s) => ({\n      key: s.split(/:|：/g)[0],\n      label: s.split(/:|：/g)[0],\n    }));\n    return { ...lowcodeContext.model, items };\n  },\n  askChatGPT: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    const res = await main.handleAskChatGPT();\n    return res;\n  },\n  intFromClipboardImage: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    const res = await main.handleIntFromClipboardImage();\n    return res;\n  },\n\n  OCR: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    const res = await main.handleOCR();\n    return res;\n  },\n};\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Descriptions 描述列表/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { CompileContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Descriptions 描述列表/script/src/main.ts",
    "content": "import * as path from 'path';\nimport * as fs from 'fs-extra';\nimport * as execa from 'execa';\nimport * as ejs from 'ejs';\nimport axios from 'axios';\nimport { workspace, window } from 'vscode';\nimport { translate } from '@share/TypeChatSlim/index';\nimport { generalBasic } from '@share/BaiduOCR/index';\nimport { typescriptToMock } from '@share/utils/json';\nimport { context } from './context';\nimport { IItems } from '../../config/schema';\n\nexport async function handleOCR() {\n  const { lowcodeContext } = context;\n  if (!lowcodeContext?.clipboardImage) {\n    window.showInformationMessage('剪贴板里没有截图');\n    return {\n      updateModelImmediately: false,\n      onlyUpdateParams: true,\n      params: '',\n      model: lowcodeContext?.model,\n    };\n  }\n  const ocrRes = await generalBasic({ image: lowcodeContext!.clipboardImage! });\n  return {\n    updateModelImmediately: false,\n    onlyUpdateParams: true,\n    params: ocrRes.words_result.map((s) => s.words).join('\\r\\n'),\n    model: lowcodeContext?.model,\n  };\n}\n\nexport async function handleAskChatGPT() {\n  const { lowcodeContext } = context;\n  const schema = fs.readFileSync(\n    path.join(lowcodeContext!.materialPath, 'config/schema.ts'),\n    'utf8',\n  );\n  const typeName = 'IItems';\n  const res = await translate<IItems>({\n    schema,\n    typeName,\n    request: JSON.stringify((lowcodeContext!.model as { items: IItems }).items),\n    completePrompt:\n      `你是一个根据以下 TypeScript 类型定义将用户请求转换为 \"${typeName}\" 类型的 JSON 对象的服务，并且按照字段的注释进行处理:\\n` +\n      `\\`\\`\\`\\n${schema}\\`\\`\\`\\n` +\n      `以下是用户请求:\\n` +\n      `\"\"\"\\n${JSON.stringify(\n        (lowcodeContext!.model as { items: IItems }).items,\n      )}\\n\"\"\"\\n` +\n      `The following is the user request translated into a JSON object with 2 spaces of indentation and no properties with the value undefined:\\n`,\n    createChatCompletion: lowcodeContext!.createChatCompletion,\n    showWebview: true,\n    extendValidate: (jsonObject) => ({ success: true, data: jsonObject }),\n  });\n  lowcodeContext!.outputChannel.appendLine(JSON.stringify(res, null, 2));\n  if (res.success) {\n    return { ...lowcodeContext!.model, items: res.data };\n  }\n  return lowcodeContext!.model;\n}\n\nexport async function handleIntFromClipboardImage() {\n  const { lowcodeContext } = context;\n  if (!lowcodeContext?.clipboardImage) {\n    window.showInformationMessage('剪贴板里获取不到图片');\n    return lowcodeContext?.model;\n  }\n  const ocrRes = await generalBasic({ image: lowcodeContext!.clipboardImage! });\n  const items: { key: string; label: string }[] = [];\n  ocrRes.words_result.map((s, index) => {\n    const includeColon = s.words.includes(':') || s.words.includes('：');\n    if (includeColon) {\n      const work = s.words.split(/:|：/g)[0];\n      items.push({\n        key: work,\n        label: work,\n      });\n    } else if (index % 2 === 0) {\n      const work = s.words.split(/:|：/g)[0];\n      items.push({\n        key: work,\n        label: work,\n      });\n    }\n  });\n  const schema = fs.readFileSync(\n    path.join(lowcodeContext!.materialPath, 'config/schema.ts'),\n    'utf8',\n  );\n  const typeName = 'IItems';\n  const res = await translate<IItems>({\n    schema,\n    typeName,\n    request: JSON.stringify(items),\n    completePrompt:\n      `你是一个根据以下 TypeScript 类型定义将用户请求转换为 \"${typeName}\" 类型的 JSON 对象的服务，并且按照字段的注释进行处理:\\n` +\n      `\\`\\`\\`\\n${schema}\\`\\`\\`\\n` +\n      `以下是用户请求:\\n` +\n      `\"\"\"\\n${JSON.stringify(items)}\\n\"\"\"\\n` +\n      `The following is the user request translated into a JSON object with 2 spaces of indentation and no properties with the value undefined:\\n`,\n    createChatCompletion: lowcodeContext!.createChatCompletion,\n    showWebview: true,\n    extendValidate: (jsonObject) => ({ success: true, data: jsonObject }),\n  });\n  lowcodeContext!.outputChannel.appendLine(JSON.stringify(res, null, 2));\n  if (res.success) {\n    return { ...lowcodeContext!.model, items: res.data };\n  }\n  return { ...lowcodeContext.model };\n}\n\nexport async function handleComplete() {\n  const { lowcodeContext } = context;\n  const createBlockPath = context.lowcodeContext?.createBlockPath;\n  if (createBlockPath) {\n    // #region 更新 api.ts 文件\n    const apiFileContent = fs\n      .readFileSync(path.join(createBlockPath, 'temp.api.ts'))\n      .toString();\n\n    let apiFileContentOld = '';\n    try {\n      apiFileContentOld = fs\n        .readFileSync(path.join(createBlockPath, 'api.ts').toString())\n        .toString();\n    } catch {}\n\n    fs.writeFileSync(\n      path.join(createBlockPath, 'api.ts'),\n      apiFileContentOld + apiFileContent,\n    );\n    fs.removeSync(path.join(createBlockPath, 'temp.api.ts'));\n    try {\n      execa.sync('node', [\n        path.join(workspace.rootPath!, '/node_modules/eslint/bin/eslint.js'),\n        path.join(createBlockPath, 'api.ts'),\n        '--resolve-plugins-relative-to',\n        workspace.rootPath!,\n        '--fix',\n      ]);\n    } catch (err) {\n      console.log(err);\n    }\n    // #endregion\n\n    // #region 更新 model.ts 文件\n    const modelFileContent = fs\n      .readFileSync(path.join(createBlockPath, 'temp.model.ts'))\n      .toString();\n    let modelFileContentOld = fs\n      .readFileSync(path.join(createBlockPath, 'model.ts').toString())\n      .toString();\n\n    const keywords = [\n      '// lowcode-model-import-api',\n      '// lowcode-model-type',\n      '// lowcode-model-variable',\n      '// lowcode-model-return-variable',\n    ];\n    const modelSplitArr = modelFileContent.split(\n      new RegExp(keywords.join('|'), 'ig'),\n    );\n    const modelImportApi = modelSplitArr[1].replace(/\\n/g, '');\n    const modelType = modelSplitArr[2];\n    const modelVariable = modelSplitArr[3];\n    const modelReturnVariable = modelSplitArr[4].replace(/\\n/g, '');\n\n    if (!modelFileContentOld.includes('// lowcode-model-import-api')) {\n      modelFileContentOld = `// lowcode-model-import-api\\n${modelFileContentOld}`;\n    }\n    modelFileContentOld = modelFileContentOld.replace(\n      '// lowcode-model-import-api',\n      modelImportApi,\n    );\n\n    if (!modelFileContentOld.includes('// lowcode-model-type')) {\n      modelFileContentOld = modelFileContentOld.replace(\n        'export const useModel',\n        '// lowcode-model-type\\nexport const useModel',\n      );\n    }\n    modelFileContentOld = modelFileContentOld.replace(\n      '// lowcode-model-type',\n      modelType,\n    );\n\n    if (!modelFileContentOld.includes('// lowcode-model-variable')) {\n      modelFileContentOld = modelFileContentOld.replace(\n        'return {',\n        '// lowcode-model-variable\\nreturn {',\n      );\n    }\n    modelFileContentOld = modelFileContentOld.replace(\n      '// lowcode-model-variable',\n      modelVariable,\n    );\n\n    if (!modelFileContentOld.includes('// lowcode-model-return-variable')) {\n      modelFileContentOld = modelFileContentOld.replace(\n        'return {',\n        'return {\\n// lowcode-model-return-variable',\n      );\n    }\n    modelFileContentOld = modelFileContentOld.replace(\n      '// lowcode-model-return-variable',\n      modelReturnVariable,\n    );\n\n    fs.writeFileSync(\n      path.join(createBlockPath, 'model.ts'),\n      modelFileContentOld,\n    );\n    fs.removeSync(path.join(createBlockPath, 'temp.model.ts'));\n    try {\n      execa.sync('node', [\n        path.join(workspace.rootPath!, '/node_modules/eslint/bin/eslint.js'),\n        path.join(createBlockPath, 'model.ts'),\n        '--resolve-plugins-relative-to',\n        workspace.rootPath!,\n        '--fix',\n      ]);\n    } catch (err) {\n      console.log(err);\n    }\n    // #endregion\n\n    // #region 更新 service.ts 文件\n    const serviceFileContent = fs\n      .readFileSync(path.join(createBlockPath, 'temp.service.ts').toString())\n      .toString();\n    let serviceFileContentOld = fs\n      .readFileSync(path.join(createBlockPath, 'service.ts').toString())\n      .toString()\n      .trim();\n\n    const serviceSplitArr = serviceFileContent.split(\n      new RegExp(\n        ['// lowcode-service-import-api', '// lowcode-service-method'].join(\n          '|',\n        ),\n        'ig',\n      ),\n    );\n    const serviceImportApi = serviceSplitArr[1].replace(/\\n/g, '');\n    const serviceMethod = serviceSplitArr[2];\n    if (!serviceFileContentOld.includes('// lowcode-service-import-api')) {\n      serviceFileContentOld = `// lowcode-service-import-api\\n${serviceFileContentOld}`;\n    }\n    serviceFileContentOld = serviceFileContentOld.replace(\n      '// lowcode-service-import-api',\n      serviceImportApi,\n    );\n\n    if (!serviceFileContentOld.includes('// lowcode-service-method')) {\n      serviceFileContentOld = `${serviceFileContentOld.slice(\n        0,\n        serviceFileContentOld.length - 1,\n      )}// lowcode-service-method\\n}`;\n    }\n    serviceFileContentOld = serviceFileContentOld.replace(\n      '// lowcode-service-method',\n      serviceMethod,\n    );\n    fs.writeFileSync(\n      path.join(createBlockPath, 'service.ts'),\n      serviceFileContentOld,\n    );\n    fs.removeSync(path.join(createBlockPath, 'temp.service.ts'));\n    try {\n      execa.sync('node', [\n        path.join(workspace.rootPath!, '/node_modules/eslint/bin/eslint.js'),\n        path.join(createBlockPath, 'service.ts'),\n        '--resolve-plugins-relative-to',\n        workspace.rootPath!,\n        '--fix',\n      ]);\n    } catch (err) {\n      console.log(err);\n    }\n    // #endregion\n\n    // #region 更新 index.vue 文件\n    const vueFileContent = fs\n      .readFileSync(path.join(createBlockPath, 'temp.index.vue').toString())\n      .toString();\n\n    let vueFileContentOld = fs\n      .readFileSync(path.join(createBlockPath, 'index.vue').toString())\n      .toString();\n\n    const vueSplitArr = vueFileContent.split(\n      new RegExp(['<!-- lowcode-vue-template -->'].join('|'), 'ig'),\n    );\n    const vueTemplate = vueSplitArr[1];\n\n    if (!vueFileContentOld.includes('<!-- lowcode-vue-template -->')) {\n      const index = vueFileContentOld.lastIndexOf('</template>');\n      vueFileContentOld = `${vueFileContentOld.substring(\n        0,\n        index,\n      )}<!-- lowcode-vue-template -->${vueFileContentOld.substring(index)}`;\n    }\n    vueFileContentOld = vueFileContentOld.replace(\n      '<!-- lowcode-vue-template -->',\n      vueTemplate,\n    );\n\n    fs.writeFileSync(\n      path.join(createBlockPath, 'index.vue'),\n      vueFileContentOld,\n    );\n    fs.removeSync(path.join(createBlockPath, 'temp.index.vue'));\n    try {\n      execa.sync('node', [\n        path.join(workspace.rootPath!, '/node_modules/eslint/bin/eslint.js'),\n        path.join(createBlockPath, 'index.vue'),\n        '--resolve-plugins-relative-to',\n        workspace.rootPath!,\n        '--fix',\n      ]);\n    } catch (err) {\n      console.log(err);\n    }\n    // #endregion\n\n    // #region 更新 mock 服务\n    const mockType = fs\n      .readFileSync(path.join(createBlockPath, 'temp.mock.type').toString())\n      .toString();\n    fs.removeSync(path.join(createBlockPath, 'temp.mock.type'));\n    const { mockCode, mockData } = typescriptToMock(mockType);\n    const mockTemplate = fs\n      .readFileSync(path.join(createBlockPath, 'temp.mock.script').toString())\n      .toString();\n    fs.removeSync(path.join(createBlockPath, 'temp.mock.script'));\n    const mockScript = ejs.render(mockTemplate, {\n      ...lowcodeContext!.model,\n      mockCode,\n      mockData,\n      createBlockPath: createBlockPath.replace(':', ''),\n    });\n    const mockProjectPathRes = await axios\n      .get('http://localhost:3000/mockProjectPath', { timeout: 1000 })\n      .catch(() => {\n        // window.showErrorMessage('获取 mock 项目路径失败');\n      });\n    if (mockProjectPathRes?.data.result) {\n      const projectName = workspace.rootPath\n        ?.replace(/\\\\/g, '/')\n        .split('/')\n        .pop();\n      const mockRouteFile = path.join(\n        mockProjectPathRes.data.result,\n        `${projectName}.js`,\n      );\n      let mockFileContent = `\n\t\t\timport KoaRouter from 'koa-router';\n\t\t\timport proxy from '../middleware/Proxy';\n\t\t\timport { delay } from '../lib/util';\n\n\t\t\tconst Mock = require('mockjs');\n\n\t\t\tconst { Random } = Mock;\n\n\t\t\tconst router = new KoaRouter();\n\t\t\trouter{{mockScript}}\n\t\t\tmodule.exports = router;\n\t\t\t`;\n\n      if (fs.existsSync(mockRouteFile)) {\n        mockFileContent = fs.readFileSync(mockRouteFile).toString().toString();\n        const index = mockFileContent.lastIndexOf(')') + 1;\n        mockFileContent = `${mockFileContent.substring(\n          0,\n          index,\n        )}{{mockScript}}\\n${mockFileContent.substring(index)}`;\n      }\n      mockFileContent = mockFileContent.replace(/{{mockScript}}/g, mockScript);\n      fs.writeFileSync(mockRouteFile, mockFileContent);\n      try {\n        execa.sync('node', [\n          path.join(\n            mockProjectPathRes.data.result\n              .replace(/\\\\/g, '/')\n              .replace('/src/routes', ''),\n            '/node_modules/eslint/bin/eslint.js',\n          ),\n          mockRouteFile,\n          '--resolve-plugins-relative-to',\n          mockProjectPathRes.data.result\n            .replace(/\\\\/g, '/')\n            .replace('/src/routes', ''),\n          '--fix',\n        ]);\n      } catch (err) {\n        console.log(err);\n      }\n      // #endregion\n    }\n  }\n}\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Descriptions 描述列表/src/temp.api.ts.ejs",
    "content": "// #region\nexport interface IFetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Result {\n  code: number;\n\tmsg: string;\n\tresult: {\n\t\t<% items.map((item, index) => { _%>\n\t\t\t<%= item.key || `item${index+1}` %>: string;\n\t\t<% }) _%>\n\t};\n}\n\nexport interface I<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Params {\n\tid?: number;\n}\n\nexport function fetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>(\n\tparams: I<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Params\n) {\n\treturn request<IFetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Result>({\n\t\turl: `http://127.0.0.1:3000<%= createBlockPath %>/fetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>`, \n\t\tmethod: 'GET',\n\t\tparams,\n\t});\n}\n// #endregion\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Descriptions 描述列表/src/temp.index.vue.ejs",
    "content": "<!-- lowcode-vue-template -->\n<a-descriptions \n\ttitle=\"<%= title %>\" \n\t:bordered=\"<%= bordered %>\"\n\t<% if(column){ _%>\n\t:column=\"<%= column %>\"\n\t<% } _%>\n\t<% if(layout){ _%>\n\tlayout=\"<%= layout %>\"\n\t<% } _%>\n>\n\t<% if(extra){ _%>\n\t<template #extra>\n\t\textra\n\t</template>\n\t<% } _%>\n\t<% items.map((item, index) => { _%>\n\t\t<a-descriptions-item \n\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t<% if(item.span){ _%>\n\t\t\t\t:span=\"<%= item.span %>\"\n\t\t\t<% } _%>\n\t\t>\n\t\t\t{{ model.<%= variableName %>.value?.<%= item.key || `item${index+1}` %> }}\n\t\t</a-descriptions-item>\n\t<% }) _%>\n</a-descriptions>\n\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Descriptions 描述列表/src/temp.mock.script",
    "content": ".get(`<%= createBlockPath %>/fetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>`, async (ctx, next) => { <%- mockCode %> ctx.body = <%- mockData %>\n})\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Descriptions 描述列表/src/temp.mock.type.ejs",
    "content": "{\n  code: number;\n\tmsg: string;\n\tresult: {\n\t\t<% items.map((item, index) => { _%>\n\t\t\t<%= item.key || `item${index+1}` %>: string;\n\t\t<% }) _%>\n\t};\n}"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Descriptions 描述列表/src/temp.model.ts.ejs",
    "content": "// lowcode-model-import-api\nimport { IFetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Result } from \"./api\";\n// lowcode-model-type\ninterface I<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %> {\n\t<% items.map((item, index) => { _%>\n\t\t/** <%= item.label %> */\n\t\t<%= item.key || `item${index+1}` %>: string;\n\t<% }) _%>\n\t/**\n   * 接口返回的数据，新增字段不需要改 I<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %> 直接从这里取\n   */\n\tapiResult: IFetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Result['result']\n}\n// lowcode-model-variable\nconst <%= variableName %> = ref<I<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %> | undefined>(\n\tundefined,\n\t\t);\n// lowcode-model-return-variable\n<%= variableName %>,\n\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Descriptions 描述列表/src/temp.service.ts.ejs",
    "content": "// lowcode-service-import-api\nimport {fetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>} from './api';\n// lowcode-service-method\nasync get<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>() {\n\tconst res = await fetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>({})\n\tthis.model.<%= variableName %>.value = {\n\t\t<% items.map((item, index) => { _%>\n\t\t\t<%= item.key || `item${index+1}` %>: res.result.<%= item.key || `item${index+1}` %>,\n\t\t<% }) _%>\n\t\tapiResult: res.result\n\t}\n}\n\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Form 垂直布局列表/config/model.json",
    "content": "{\n\t\"items\": [],\n\t\"variableName\": \"\"\n}"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Form 垂直布局列表/config/preview.json",
    "content": "{\n\t\"title\": \"\",\n\t\"description\": \"\",\n\t\"img\": [\n\t\t\"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n\t],\n\t\"category\": [],\n\t\"schema\": \"amis\",\n\t\"scripts\": [\n\t\t{\n\t\t\t\"method\": \"OCR\",\n\t\t\t\"remark\": \"OCR 识别剪贴版截图\"\n\t\t},\n\t\t{\n\t\t\t\"method\": \"initFromOcrText\",\n\t\t\t\"remark\": \"初始化列表，参数中粘贴 ocr 识别出的结果，每一行表示一项，也可以手动输入\"\n\t\t},\n\t\t{\n\t\t\t\"method\": \"askChatGPT\",\n\t\t\t\"remark\": \"使用 ChatGPT 翻译模版数据里的 items.key 字段\"\n\t\t}\n\t]\n}"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Form 垂直布局列表/config/schema.json",
    "content": "{\n\t\"formSchema\": {\n\t\t\"schema\": {\n\t\t\t\"type\": \"page\",\n\t\t\t\"body\": [\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"form\",\n\t\t\t\t\t\"id\": \"u:67967afb0e69\",\n\t\t\t\t\t\"title\": \"\",\n\t\t\t\t\t\"body\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"id\": \"u:11b127c5df46\",\n\t\t\t\t\t\t\t\"label\": \"变量名\",\n\t\t\t\t\t\t\t\"name\": \"variableName\",\n\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"combo\",\n\t\t\t\t\t\t\t\"label\": \"描述列表\",\n\t\t\t\t\t\t\t\"name\": \"items\",\n\t\t\t\t\t\t\t\"multiple\": true,\n\t\t\t\t\t\t\t\"addable\": true,\n\t\t\t\t\t\t\t\"removable\": true,\n\t\t\t\t\t\t\t\"removableMode\": \"icon\",\n\t\t\t\t\t\t\t\"addBtn\": {\n\t\t\t\t\t\t\t\t\"label\": \"新增\",\n\t\t\t\t\t\t\t\t\"icon\": \"fa fa-plus\",\n\t\t\t\t\t\t\t\t\"level\": \"primary\",\n\t\t\t\t\t\t\t\t\"size\": \"sm\",\n\t\t\t\t\t\t\t\t\"id\": \"u:47ecb9e15ff1\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"items\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"key\",\n\t\t\t\t\t\t\t\t\t\"placeholder\": \"字段名\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:25b0c7b5e5a0\",\n\t\t\t\t\t\t\t\t\t\"label\": \"字段名（key）\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"label\",\n\t\t\t\t\t\t\t\t\t\"name\": \"label\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:6496cac4f4b8\",\n\t\t\t\t\t\t\t\t\t\"description\": \"内容的描述\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"id\": \"u:186f183e9320\",\n\t\t\t\t\t\t\t\"strictMode\": false,\n\t\t\t\t\t\t\t\"syncFields\": [],\n\t\t\t\t\t\t\t\"tabsMode\": false,\n\t\t\t\t\t\t\t\"draggable\": true,\n\t\t\t\t\t\t\t\"draggableTip\": \"可拖动排序\",\n\t\t\t\t\t\t\t\"tabsStyle\": \"line\",\n\t\t\t\t\t\t\t\"tabsLabelTpl\": \"表单项${index+1}\",\n\t\t\t\t\t\t\t\"multiLine\": true,\n\t\t\t\t\t\t\t\"value\": [\n\t\t\t\t\t\t\t\t{}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\t\"submitText\": \"\"\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"id\": \"u:d87dbf6bf8df\",\n\t\t\t\"pullRefresh\": {\n\t\t\t\t\"disabled\": true\n\t\t\t},\n\t\t\t\"regions\": [\n\t\t\t\t\"body\"\n\t\t\t],\n\t\t\t\"style\": {\n\t\t\t\t\"boxShadow\": \" 0px 0px 0px 0px transparent\"\n\t\t\t},\n\t\t\t\"asideResizor\": false\n\t\t},\n\t\t\"conditionFiles\": {\n\t\t\t\"name\": {\n\t\t\t\t\"value\": \"123\",\n\t\t\t\t\"exclude\": [\n\t\t\t\t\t\"当表单name的值为123,删除这个数组里的文件.ejs\"\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"excludeCompile\": [\n\t\t\t\"不需要编译的文件,不会被删除.ejs\"\n\t\t]\n\t}\n}"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Form 垂直布局列表/config/schema.ts",
    "content": "export type IItems = {\n  /**\n   * @description 保持原始内容，不需要处理，不要翻译\n   * @type {string}\n   */\n  label: string;\n  /**\n   * @description 翻译成英文，驼峰格式\n   * @type {string}\n   */\n  key: string;\n}[];\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Form 垂直布局列表/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/blocks/现有模块中添加 antdv Form 垂直布局列表/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/blocks/现有模块中添加 antdv Form 垂直布局列表/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: (lowcodeContext) => {},\n  complete: (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    main.handleComplete();\n  },\n  initFromOcrText: (lowcodeContext) => {\n    let items = lowcodeContext.params\n      .replace(/\\r\\n/g, '\\n')\n      .replace(/\\r/g, '\\n')\n      .split('\\n');\n    items = items.map((s) => ({\n      key: s.split(/:|：/g)[0],\n      label: s.split(/:|：/g)[0],\n    }));\n    return { ...lowcodeContext.model, items };\n  },\n\n  OCR: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    const res = await main.handleOCR();\n    return res;\n  },\n  runScript: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    const res = await main.handleRunScript();\n    return res;\n  },\n};\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Form 垂直布局列表/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { CompileContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Form 垂直布局列表/script/src/main.ts",
    "content": "import * as path from 'path';\nimport * as fs from 'fs-extra';\nimport * as execa from 'execa';\nimport * as ejs from 'ejs';\nimport axios from 'axios';\nimport { workspace, window } from 'vscode';\nimport { generalBasic } from '@share/BaiduOCR/index';\nimport { translate } from '@share/TypeChatSlim/index';\nimport { typescriptToMock } from '@share/utils/json';\nimport { IItems } from '../../config/schema';\nimport { context } from './context';\n\nexport async function handleOCR() {\n  const { lowcodeContext } = context;\n  if (!lowcodeContext?.clipboardImage) {\n    window.showInformationMessage('剪贴板里没有截图');\n    return {\n      updateModelImmediately: false,\n      onlyUpdateParams: true,\n      params: '',\n      model: lowcodeContext?.model,\n    };\n  }\n  const ocrRes = await generalBasic({ image: lowcodeContext!.clipboardImage! });\n  return {\n    updateModelImmediately: false,\n    onlyUpdateParams: true,\n    params: ocrRes.words_result.map((s) => s.words).join('\\r\\n'),\n    model: lowcodeContext?.model,\n  };\n}\n\nconst scriptHandle: {\n  [method: string]: () => Promise<{\n    updateModelImmediately: boolean;\n    onlyUpdateParams: boolean;\n    params?: string;\n    model: any;\n  }>;\n} = {\n  askChatGPT: async () => {\n    const { lowcodeContext } = context;\n    const schema = fs.readFileSync(\n      path.join(lowcodeContext!.materialPath, 'config/schema.ts'),\n      'utf8',\n    );\n    const typeName = 'IItems';\n    const res = await translate<IItems>({\n      schema,\n      typeName,\n      request: JSON.stringify(\n        (lowcodeContext!.model as { items: IItems }).items,\n      ),\n      completePrompt:\n        `你是一个根据以下 TypeScript 类型定义将用户请求转换为 \"${typeName}\" 类型的 JSON 对象的服务，并且按照字段的注释进行处理:\\n` +\n        `\\`\\`\\`\\n${schema}\\`\\`\\`\\n` +\n        `以下是用户请求:\\n` +\n        `\"\"\"\\n${JSON.stringify(\n          (lowcodeContext!.model as { items: IItems }).items,\n        )}\\n\"\"\"\\n` +\n        `The following is the user request translated into a JSON object with 2 spaces of indentation and no properties with the value undefined:\\n`,\n      createChatCompletion: lowcodeContext!.createChatCompletion,\n      showWebview: true,\n      extendValidate: (jsonObject) => ({ success: true, data: jsonObject }),\n    });\n    lowcodeContext!.outputChannel.appendLine(JSON.stringify(res, null, 2));\n    if (res.success) {\n      return {\n        updateModelImmediately: false,\n        onlyUpdateParams: false,\n        params: '',\n        model: { ...lowcodeContext?.model, items: res.data },\n      };\n    }\n    return {\n      updateModelImmediately: false,\n      onlyUpdateParams: false,\n      params: '',\n      model: lowcodeContext?.model,\n    };\n  },\n};\n\nexport async function handleRunScript() {\n  const { lowcodeContext } = context;\n  const res = await scriptHandle[lowcodeContext!.method]();\n  return res;\n}\n\nexport async function handleComplete() {\n  const { lowcodeContext } = context;\n  const createBlockPath = context.lowcodeContext?.createBlockPath;\n  if (createBlockPath) {\n    // #region 更新 api.ts 文件\n    const apiFileContent = fs\n      .readFileSync(path.join(createBlockPath, 'temp.api.ts'))\n      .toString();\n\n    let apiFileContentOld = '';\n    try {\n      apiFileContentOld = fs\n        .readFileSync(path.join(createBlockPath, 'api.ts').toString())\n        .toString();\n    } catch {}\n\n    fs.writeFileSync(\n      path.join(createBlockPath, 'api.ts'),\n      apiFileContentOld + apiFileContent,\n    );\n    fs.removeSync(path.join(createBlockPath, 'temp.api.ts'));\n    // #endregion\n\n    // #region 更新 model.ts 文件\n    const modelFileContent = fs\n      .readFileSync(path.join(createBlockPath, 'temp.model.ts'))\n      .toString();\n    let modelFileContentOld = fs\n      .readFileSync(path.join(createBlockPath, 'model.ts').toString())\n      .toString();\n\n    const keywords = [\n      '// lowcode-model-import-api',\n      '// lowcode-model-type',\n      '// lowcode-model-variable',\n      '// lowcode-model-return-variable',\n    ];\n    const modelSplitArr = modelFileContent.split(\n      new RegExp(keywords.join('|'), 'ig'),\n    );\n    const modelImportApi = modelSplitArr[1].replace(/\\n/g, '');\n    const modelType = modelSplitArr[2];\n    const modelVariable = modelSplitArr[3];\n    const modelReturnVariable = modelSplitArr[4].replace(/\\n/g, '');\n\n    if (!modelFileContentOld.includes('// lowcode-model-import-api')) {\n      modelFileContentOld = `// lowcode-model-import-api\\n${modelFileContentOld}`;\n    }\n    modelFileContentOld = modelFileContentOld.replace(\n      '// lowcode-model-import-api',\n      modelImportApi,\n    );\n\n    if (!modelFileContentOld.includes('// lowcode-model-type')) {\n      modelFileContentOld = modelFileContentOld.replace(\n        'export const useModel',\n        '// lowcode-model-type\\nexport const useModel',\n      );\n    }\n    modelFileContentOld = modelFileContentOld.replace(\n      '// lowcode-model-type',\n      modelType,\n    );\n\n    if (!modelFileContentOld.includes('// lowcode-model-variable')) {\n      modelFileContentOld = modelFileContentOld.replace(\n        'return {',\n        '// lowcode-model-variable\\nreturn {',\n      );\n    }\n    modelFileContentOld = modelFileContentOld.replace(\n      '// lowcode-model-variable',\n      modelVariable,\n    );\n\n    if (!modelFileContentOld.includes('// lowcode-model-return-variable')) {\n      modelFileContentOld = modelFileContentOld.replace(\n        'return {',\n        'return {\\n// lowcode-model-return-variable',\n      );\n    }\n    modelFileContentOld = modelFileContentOld.replace(\n      '// lowcode-model-return-variable',\n      modelReturnVariable,\n    );\n\n    fs.writeFileSync(\n      path.join(createBlockPath, 'model.ts'),\n      modelFileContentOld,\n    );\n    fs.removeSync(path.join(createBlockPath, 'temp.model.ts'));\n    // #endregion\n\n    // #region 更新 service.ts 文件\n    const serviceFileContent = fs\n      .readFileSync(path.join(createBlockPath, 'temp.service.ts').toString())\n      .toString();\n    let serviceFileContentOld = fs\n      .readFileSync(path.join(createBlockPath, 'service.ts').toString())\n      .toString()\n      .trim();\n\n    const serviceSplitArr = serviceFileContent.split(\n      new RegExp(\n        ['// lowcode-service-import-api', '// lowcode-service-method'].join(\n          '|',\n        ),\n        'ig',\n      ),\n    );\n    const serviceImportApi = serviceSplitArr[1].replace(/\\n/g, '');\n    const serviceMethod = serviceSplitArr[2];\n    if (!serviceFileContentOld.includes('// lowcode-service-import-api')) {\n      serviceFileContentOld = `// lowcode-service-import-api\\n${serviceFileContentOld}`;\n    }\n    serviceFileContentOld = serviceFileContentOld.replace(\n      '// lowcode-service-import-api',\n      serviceImportApi,\n    );\n\n    if (!serviceFileContentOld.includes('// lowcode-service-method')) {\n      serviceFileContentOld = `${serviceFileContentOld.slice(\n        0,\n        serviceFileContentOld.length - 1,\n      )}// lowcode-service-method\\n}`;\n    }\n    serviceFileContentOld = serviceFileContentOld.replace(\n      '// lowcode-service-method',\n      serviceMethod,\n    );\n    fs.writeFileSync(\n      path.join(createBlockPath, 'service.ts'),\n      serviceFileContentOld,\n    );\n    fs.removeSync(path.join(createBlockPath, 'temp.service.ts'));\n\n    // #endregion\n\n    // #region 更新 index.vue 文件\n    const vueFileContent = fs\n      .readFileSync(path.join(createBlockPath, 'temp.index.vue').toString())\n      .toString();\n\n    let vueFileContentOld = fs\n      .readFileSync(path.join(createBlockPath, 'index.vue').toString())\n      .toString();\n\n    const vueSplitArr = vueFileContent.split(\n      new RegExp(['<!-- lowcode-vue-template -->'].join('|'), 'ig'),\n    );\n    const vueTemplate = vueSplitArr[1];\n\n    if (!vueFileContentOld.includes('<!-- lowcode-vue-template -->')) {\n      const index = vueFileContentOld.lastIndexOf('</template>');\n      vueFileContentOld = `${vueFileContentOld.substring(\n        0,\n        index,\n      )}<!-- lowcode-vue-template -->${vueFileContentOld.substring(index)}`;\n    }\n    vueFileContentOld = vueFileContentOld.replace(\n      '<!-- lowcode-vue-template -->',\n      vueTemplate,\n    );\n\n    fs.writeFileSync(\n      path.join(createBlockPath, 'index.vue'),\n      vueFileContentOld,\n    );\n    fs.removeSync(path.join(createBlockPath, 'temp.index.vue'));\n    // #endregion\n\n    // #region 更新 mock 服务\n    const mockType = fs\n      .readFileSync(path.join(createBlockPath, 'temp.mock.type').toString())\n      .toString();\n    fs.removeSync(path.join(createBlockPath, 'temp.mock.type'));\n    const { mockCode, mockData } = typescriptToMock(mockType);\n    const mockTemplate = fs\n      .readFileSync(path.join(createBlockPath, 'temp.mock.script').toString())\n      .toString();\n    fs.removeSync(path.join(createBlockPath, 'temp.mock.script'));\n    const mockScript = ejs.render(mockTemplate, {\n      ...lowcodeContext!.model,\n      mockCode,\n      mockData,\n      createBlockPath: createBlockPath.replace(':', ''),\n    });\n    const mockProjectPathRes = await axios\n      .get('http://localhost:3000/mockProjectPath', { timeout: 1000 })\n      .catch(() => {\n        // window.showErrorMessage('获取 mock 项目路径失败');\n      });\n    if (mockProjectPathRes?.data.result) {\n      const projectName = workspace.rootPath\n        ?.replace(/\\\\/g, '/')\n        .split('/')\n        .pop();\n      const mockRouteFile = path.join(\n        mockProjectPathRes.data.result,\n        `${projectName}.js`,\n      );\n      let mockFileContent = `\n\timport KoaRouter from 'koa-router';\n\timport proxy from '../middleware/Proxy';\n\timport { delay } from '../lib/util';\n\n\tconst Mock = require('mockjs');\n\n\tconst { Random } = Mock;\n\n\tconst router = new KoaRouter();\n\trouter{{mockScript}}\n\tmodule.exports = router;\n\t`;\n\n      if (fs.existsSync(mockRouteFile)) {\n        mockFileContent = fs.readFileSync(mockRouteFile).toString().toString();\n        const index = mockFileContent.lastIndexOf(')') + 1;\n        mockFileContent = `${mockFileContent.substring(\n          0,\n          index,\n        )}{{mockScript}}\\n${mockFileContent.substring(index)}`;\n      }\n      mockFileContent = mockFileContent.replace(/{{mockScript}}/g, mockScript);\n      fs.writeFileSync(mockRouteFile, mockFileContent);\n      try {\n        execa.sync('node', [\n          path.join(\n            mockProjectPathRes.data.result\n              .replace(/\\\\/g, '/')\n              .replace('/src/routes', ''),\n            '/node_modules/eslint/bin/eslint.js',\n          ),\n          mockRouteFile,\n          '--resolve-plugins-relative-to',\n          mockProjectPathRes.data.result\n            .replace(/\\\\/g, '/')\n            .replace('/src/routes', ''),\n          '--fix',\n        ]);\n      } catch (err) {\n        console.log(err);\n      }\n    }\n    // #endregion\n  }\n}\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Form 垂直布局列表/src/temp.api.ts.ejs",
    "content": "// #region\nexport interface IFetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Result {\n  code: number;\n\tmsg: string;\n\tresult: {\n\t\t<% items.map((item, index) => { _%>\n\t\t\t<%= item.key || `item${index+1}` %>: string;\n\t\t<% }) _%>\n\t};\n}\n\nexport interface I<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Params {\n\tid?: number;\n}\n\nexport function fetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>(\n\tparams: I<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Params\n) {\n\treturn request<IFetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Result>({\n\t\turl: `http://127.0.0.1:3000<%= createBlockPath %>/fetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>`, \n\t\tmethod: 'GET',\n\t\tparams,\n\t});\n}\n// #endregion\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Form 垂直布局列表/src/temp.index.vue.ejs",
    "content": "<!-- lowcode-vue-template -->\n<a-form :label-col=\"{ span: 4 }\" :wrapper-col=\"{ span: 12 }\">\n\t<% items.map((item, index) => { _%>\n\t\t<a-form-item\n\t\t\tlabel=\"<%= item.label %>\"\n\t\t>\n\t\t\t{{ model.<%= variableName %>.value?.<%= item.key || `item${index+1}` %> }}\n\t\t</a-form-item>\n\t<% }) _%>\n</a-form>\n\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Form 垂直布局列表/src/temp.mock.script",
    "content": ".get(`<%= createBlockPath %>/fetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>`, async (ctx, next) => { <%- mockCode %> ctx.body = <%- mockData %>\n})\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Form 垂直布局列表/src/temp.mock.type.ejs",
    "content": "{\n  code: number;\n\tmsg: string;\n\tresult: {\n\t\t<% items.map((item, index) => { _%>\n\t\t\t<%= item.key || `item${index+1}` %>: string;\n\t\t<% }) _%>\n\t};\n}"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Form 垂直布局列表/src/temp.model.ts.ejs",
    "content": "// lowcode-model-import-api\nimport { IFetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Result } from \"./api\";\n// lowcode-model-type\ninterface I<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %> {\n\t<% items.map((item, index) => { _%>\n\t\t/** <%= item.label %> */\n\t\t<%= item.key || `item${index+1}` %>: string;\n\t<% }) _%>\n\t/**\n   * 接口返回的数据，新增字段不需要改 I<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %> 直接从这里取\n   */\n\tapiResult: IFetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Result['result']\n}\n// lowcode-model-variable\nconst <%= variableName %> = ref<I<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %> | undefined>(\n\tundefined,\n\t\t);\n// lowcode-model-return-variable\n<%= variableName %>,\n\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Form 垂直布局列表/src/temp.service.ts.ejs",
    "content": "// lowcode-service-import-api\nimport {fetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>} from './api';\n// lowcode-service-method\nasync get<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>() {\n\tconst res = await fetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>({})\n\tthis.model.<%= variableName %>.value = {\n\t\t<% items.map((item, index) => { _%>\n\t\t\t<%= item.key || `item${index+1}` %>: res.result.<%= item.key || `item${index+1}` %>,\n\t\t<% }) _%>\n\t\tapiResult: res.result\n\t}\n}\n\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Form 表单/config/model.json",
    "content": "{\n\t\"variableName\": \"\",\n\t\"formItems\": []\n}"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Form 表单/config/preview.json",
    "content": "{\n\t\"title\": \"\",\n\t\"description\": \"\",\n\t\"img\": [\n\t\t\"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n\t],\n\t\"category\": [],\n\t\"schema\": \"form-render\",\n\t\"scripts\": [\n\t\t{\n\t\t\t\"method\": \"OCR\",\n\t\t\t\"remark\": \"OCR 识别剪贴版截图\"\n\t\t},\n\t\t{\n\t\t\t\"method\": \"initFromOcrText\",\n\t\t\t\"remark\": \"初始化列表，参数中粘贴 ocr 识别出的结果，每一行表示一项，也可以手动输入\"\n\t\t},\n\t\t{\n\t\t\t\"method\": \"askChatGPT\",\n\t\t\t\"remark\": \"使用 ChatGPT 翻译模版数据里的 formItems.key 字段\"\n\t\t}\n\t]\n}"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Form 表单/config/schema.json",
    "content": "{\n\t\"formSchema\": {\n\t\t\"schema\": {\n\t\t\t\"type\": \"object\",\n\t\t\t\"column\": 1,\n\t\t\t\"labelWidth\": 120,\n\t\t\t\"displayType\": \"column\",\n\t\t\t\"properties\": {\n\t\t\t\t\"variableName\": {\n\t\t\t\t\t\"title\": \"变量名\",\n\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\"hidden\": false,\n\t\t\t\t\t\"props\": {}\n\t\t\t\t},\n\t\t\t\t\"formItems\": {\n\t\t\t\t\t\"title\": \"表单项\",\n\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\"key\": {\n\t\t\t\t\t\t\t\t\"title\": \"字段名\",\n\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\"props\": {}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"type\": {\n\t\t\t\t\t\t\t\t\"title\": \"字段类型\",\n\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\"enum\": [\n\t\t\t\t\t\t\t\t\t\"string\",\n\t\t\t\t\t\t\t\t\t\"number\",\n\t\t\t\t\t\t\t\t\t\"boolean\",\n\t\t\t\t\t\t\t\t\t\"Dayjs\",\n\t\t\t\t\t\t\t\t\t\"string[]\",\n\t\t\t\t\t\t\t\t\t\"number[]\",\n\t\t\t\t\t\t\t\t\t\"boolean[]\",\n\t\t\t\t\t\t\t\t\t\"[Dayjs,Dayjs]\",\n\t\t\t\t\t\t\t\t\t\"{name?:string;url:string}[]\"\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\"enumNames\": [\n\t\t\t\t\t\t\t\t\t\"string\",\n\t\t\t\t\t\t\t\t\t\"number\",\n\t\t\t\t\t\t\t\t\t\"boolean\",\n\t\t\t\t\t\t\t\t\t\"Dayjs\",\n\t\t\t\t\t\t\t\t\t\"string[]\",\n\t\t\t\t\t\t\t\t\t\"number[]\",\n\t\t\t\t\t\t\t\t\t\"boolean[]\",\n\t\t\t\t\t\t\t\t\t\"[Dayjs,Dayjs]\",\n\t\t\t\t\t\t\t\t\t\"图片、文件上传选此项，默认值选空数组\"\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\"widget\": \"select\",\n\t\t\t\t\t\t\t\t\"default\": \"string\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"optional\": {\n\t\t\t\t\t\t\t\t\"title\": \"字段可选\",\n\t\t\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\t\t\"widget\": \"switch\",\n\t\t\t\t\t\t\t\t\"description\": \"字段名字后加?\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"defaultValue\": {\n\t\t\t\t\t\t\t\t\"title\": \"默认值\",\n\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\"enum\": [\n\t\t\t\t\t\t\t\t\t\"\\\"\\\"\",\n\t\t\t\t\t\t\t\t\t\"false\",\n\t\t\t\t\t\t\t\t\t\"boolean\",\n\t\t\t\t\t\t\t\t\t\"true\",\n\t\t\t\t\t\t\t\t\t\"0\",\n\t\t\t\t\t\t\t\t\t\"undefined\",\n\t\t\t\t\t\t\t\t\t\"[]\"\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\"enumNames\": [\n\t\t\t\t\t\t\t\t\t\"\\\"\\\"\",\n\t\t\t\t\t\t\t\t\t\"false\",\n\t\t\t\t\t\t\t\t\t\"boolean\",\n\t\t\t\t\t\t\t\t\t\"true\",\n\t\t\t\t\t\t\t\t\t\"0\",\n\t\t\t\t\t\t\t\t\t\"undefined\",\n\t\t\t\t\t\t\t\t\t\"[]\"\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\"widget\": \"select\",\n\t\t\t\t\t\t\t\t\"default\": \"\\\"\\\"\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"component\": {\n\t\t\t\t\t\t\t\t\"title\": \"组件\",\n\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\"enum\": [\n\t\t\t\t\t\t\t\t\t\"input\",\n\t\t\t\t\t\t\t\t\t\"input-password\",\n\t\t\t\t\t\t\t\t\t\"input-number\",\n\t\t\t\t\t\t\t\t\t\"textarea\",\n\t\t\t\t\t\t\t\t\t\"select\",\n\t\t\t\t\t\t\t\t\t\"radio-group\",\n\t\t\t\t\t\t\t\t\t\"checkbox-group\",\n\t\t\t\t\t\t\t\t\t\"switch\",\n\t\t\t\t\t\t\t\t\t\"date-picker\",\n\t\t\t\t\t\t\t\t\t\"time-picker\",\n\t\t\t\t\t\t\t\t\t\"range-picker\",\n\t\t\t\t\t\t\t\t\t\"transfer\",\n\t\t\t\t\t\t\t\t\t\"uploadFiles\"\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\"enumNames\": [\n\t\t\t\t\t\t\t\t\t\"input\",\n\t\t\t\t\t\t\t\t\t\"input-password\",\n\t\t\t\t\t\t\t\t\t\"input-number\",\n\t\t\t\t\t\t\t\t\t\"textarea\",\n\t\t\t\t\t\t\t\t\t\"select\",\n\t\t\t\t\t\t\t\t\t\"radio-group\",\n\t\t\t\t\t\t\t\t\t\"checkbox-group\",\n\t\t\t\t\t\t\t\t\t\"switch\",\n\t\t\t\t\t\t\t\t\t\"date-picker\",\n\t\t\t\t\t\t\t\t\t\"time-picker\",\n\t\t\t\t\t\t\t\t\t\"range-picker\",\n\t\t\t\t\t\t\t\t\t\"transfer\",\n\t\t\t\t\t\t\t\t\t\"uploadFiles（图片、文件上传）\"\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\"widget\": \"select\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"label\": {\n\t\t\t\t\t\t\t\t\"title\": \"label\",\n\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\"props\": {}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"placeholder\": {\n\t\t\t\t\t\t\t\t\"title\": \"placeholder\",\n\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\"props\": {}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"required\": {\n\t\t\t\t\t\t\t\t\"title\": \"是否必填\",\n\t\t\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\t\t\"widget\": \"switch\",\n\t\t\t\t\t\t\t\t\"description\": \"验证规则加required\",\n\t\t\t\t\t\t\t\t\"required\": false\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"message\": {\n\t\t\t\t\t\t\t\t\"title\": \"校验失败 message\",\n\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\"default\": \"不能为空\",\n\t\t\t\t\t\t\t\t\"props\": {}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"showMore\": {\n\t\t\t\t\t\t\t\t\"title\": \"更多组件配置\",\n\t\t\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\t\t\"widget\": \"switch\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"labelInValue\": {\n\t\t\t\t\t\t\t\t\"title\": \"labelInValue\",\n\t\t\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\t\t\"widget\": \"switch\",\n\t\t\t\t\t\t\t\t\"description\": \"是否把每个选项的 label 包装到 value 中\",\n\t\t\t\t\t\t\t\t\"index\": 0,\n\t\t\t\t\t\t\t\t\"hidden\": \"{{rootValue.showMore !== true || rootValue.component !== 'select'}}\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"mode\": {\n\t\t\t\t\t\t\t\t\"title\": \"mode\",\n\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\"enum\": [\n\t\t\t\t\t\t\t\t\t\"multiple\",\n\t\t\t\t\t\t\t\t\t\"tags\"\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\"enumNames\": [\n\t\t\t\t\t\t\t\t\t\"multiple\",\n\t\t\t\t\t\t\t\t\t\"tags\"\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\"widget\": \"select\",\n\t\t\t\t\t\t\t\t\"description\": \"设置 Select 的模式为多选或标签\",\n\t\t\t\t\t\t\t\t\"index\": 1,\n\t\t\t\t\t\t\t\t\"hidden\": \"{{rootValue.showMore !== true || rootValue.component !== 'select'}}\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"optionFilterProp\": {\n\t\t\t\t\t\t\t\t\"title\": \"optionFilterProp\",\n\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\"description\": \"搜索时过滤对应的 option 属性\",\n\t\t\t\t\t\t\t\t\"default\": \"label\",\n\t\t\t\t\t\t\t\t\"props\": {},\n\t\t\t\t\t\t\t\t\"hidden\": \"{{rootValue.showMore !== true || rootValue.component !== 'select'}}\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"showSearch\": {\n\t\t\t\t\t\t\t\t\"title\": \"showSearch\",\n\t\t\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\t\t\"widget\": \"switch\",\n\t\t\t\t\t\t\t\t\"description\": \"使单选模式可搜索\",\n\t\t\t\t\t\t\t\t\"hidden\": \"{{rootValue.showMore !== true || rootValue.component !== 'select'}}\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"hideArrow\": {\n\t\t\t\t\t\t\t\t\"title\": \"hideArrow\",\n\t\t\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\t\t\"widget\": \"switch\",\n\t\t\t\t\t\t\t\t\"description\": \"是否隐藏下拉小箭头\",\n\t\t\t\t\t\t\t\t\"hidden\": \"{{rootValue.showMore !== true || rootValue.component !== 'select'}}\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"maxlength\": {\n\t\t\t\t\t\t\t\t\"title\": \"maxlength\",\n\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\"description\": \"最大长度\",\n\t\t\t\t\t\t\t\t\"hidden\": \"{{rootValue.showMore !== true || (rootValue.component !== 'input' && rootValue.component !== 'input-password' && rootValue.component !== 'textarea')}}\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"showCount\": {\n\t\t\t\t\t\t\t\t\"title\": \"showCount\",\n\t\t\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\t\t\"widget\": \"switch\",\n\t\t\t\t\t\t\t\t\"description\": \"是否展示字数\",\n\t\t\t\t\t\t\t\t\"hidden\": \"{{rootValue.showMore !== true || (rootValue.component !== 'input' && rootValue.component !== 'input-password' && rootValue.component !== 'textarea')}}\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"max\": {\n\t\t\t\t\t\t\t\t\"title\": \"max\",\n\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\"description\": \"最大值\",\n\t\t\t\t\t\t\t\t\"hidden\": \"{{rootValue.showMore !== true || (rootValue.component !== 'input-number')}}\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"min\": {\n\t\t\t\t\t\t\t\t\"title\": \"min\",\n\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\"description\": \"最小值\",\n\t\t\t\t\t\t\t\t\"hidden\": \"{{rootValue.showMore !== true || (rootValue.component !== 'input-number')}}\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"step\": {\n\t\t\t\t\t\t\t\t\"title\": \"step\",\n\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\"description\": \"每次改变步数，可以为小数\",\n\t\t\t\t\t\t\t\t\"hidden\": \"{{rootValue.showMore !== true || (rootValue.component !== 'input-number')}}\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"checkedChildren\": {\n\t\t\t\t\t\t\t\t\"title\": \"checkedChildren\",\n\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\"description\": \"选中时的内容\",\n\t\t\t\t\t\t\t\t\"hidden\": \"{{rootValue.showMore !== true || (rootValue.component !== 'switch')}}\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"unCheckedChildren\": {\n\t\t\t\t\t\t\t\t\"title\": \"unCheckedChildren\",\n\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\"description\": \"非选中时的内容\",\n\t\t\t\t\t\t\t\t\"hidden\": \"{{rootValue.showMore !== true || (rootValue.component !== 'switch')}}\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"checkedValue\": {\n\t\t\t\t\t\t\t\t\"title\": \"checkedValue\",\n\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\"description\": \"选中时的值\",\n\t\t\t\t\t\t\t\t\"hidden\": \"{{rootValue.showMore !== true || (rootValue.component !== 'switch')}}\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"unCheckedValue\": {\n\t\t\t\t\t\t\t\t\"title\": \"unCheckedValue\",\n\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\"description\": \"非选中时的值\",\n\t\t\t\t\t\t\t\t\"hidden\": \"{{rootValue.showMore !== true || (rootValue.component !== 'switch')}}\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"picker\": {\n\t\t\t\t\t\t\t\t\"title\": \"picker\",\n\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\"enum\": [\n\t\t\t\t\t\t\t\t\t\"date\",\n\t\t\t\t\t\t\t\t\t\"week\",\n\t\t\t\t\t\t\t\t\t\"month\",\n\t\t\t\t\t\t\t\t\t\"quarter\",\n\t\t\t\t\t\t\t\t\t\"year\"\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\"enumNames\": [\n\t\t\t\t\t\t\t\t\t\"date\",\n\t\t\t\t\t\t\t\t\t\"week\",\n\t\t\t\t\t\t\t\t\t\"month\",\n\t\t\t\t\t\t\t\t\t\"quarter\",\n\t\t\t\t\t\t\t\t\t\"year\"\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\"widget\": \"select\",\n\t\t\t\t\t\t\t\t\"description\": \"设置选择器类型\",\n\t\t\t\t\t\t\t\t\"hidden\": \"{{rootValue.showMore !== true || (rootValue.component !== 'date-picker' && rootValue.component !== 'range-picker')}}\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"showTime\": {\n\t\t\t\t\t\t\t\t\"title\": \"showTime\",\n\t\t\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\t\t\"widget\": \"switch\",\n\t\t\t\t\t\t\t\t\"description\": \"增加时间选择功能\",\n\t\t\t\t\t\t\t\t\"hidden\": \"{{rootValue.showMore !== true || (rootValue.component !== 'date-picker' && rootValue.component !== 'range-picker' || rootValue.picker !== 'date')}}\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"showNow\": {\n\t\t\t\t\t\t\t\t\"title\": \"showNow\",\n\t\t\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\t\t\"widget\": \"switch\",\n\t\t\t\t\t\t\t\t\"description\": \"当设定了 showTime 的时候，面板是否显示“此刻”按钮\",\n\t\t\t\t\t\t\t\t\"hidden\": \"{{rootValue.showMore !== true || (rootValue.component !== 'date-picker' && rootValue.component !== 'range-picker' || rootValue.picker !== 'date')}}\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"showToday\": {\n\t\t\t\t\t\t\t\t\"title\": \"showToday\",\n\t\t\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\t\t\"widget\": \"switch\",\n\t\t\t\t\t\t\t\t\"description\": \"是否展示“今天”按钮\",\n\t\t\t\t\t\t\t\t\"hidden\": \"{{rootValue.showMore !== true || (rootValue.component !== 'date-picker' && rootValue.component !== 'range-picker' || rootValue.picker !== 'date')}}\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"props\": {},\n\t\t\t\t\t\"index\": 0,\n\t\t\t\t\t\"hidden\": false\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"conditionFiles\": {\n\t\t\t\"name\": {\n\t\t\t\t\"value\": \"123\",\n\t\t\t\t\"exclude\": [\n\t\t\t\t\t\"当表单name的值为123,删除这个数组里的文件.ejs\"\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"excludeCompile\": [\n\t\t\t\"不需要编译的文件,不会被删除.ejs\"\n\t\t]\n\t}\n}"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Form 表单/config/schema.ts",
    "content": "export type IFormItems = {\n  /**\n   * @description 保持原始内容，不需要处理，不要翻译\n   * @type {string}\n   */\n  label: string;\n  /**\n   * @description 翻译成英文，驼峰格式\n   * @type {string}\n   */\n  key: string;\n  /**\n   * @description 保持原始内容，不需要处理，不要翻译\n   * @type {string}\n   */\n  placeholder: string;\n}[];\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Form 表单/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/blocks/现有模块中添加 antdv Form 表单/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/blocks/现有模块中添加 antdv Form 表单/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: (lowcodeContext) => {},\n  complete: (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    main.handleComplete();\n  },\n  initFromOcrText: (lowcodeContext) => {\n    let formItems = lowcodeContext.params\n      .replace(/\\r\\n/g, '\\n')\n      .replace(/\\r/g, '\\n')\n      .split('\\n');\n    formItems = formItems.map((s) => ({\n      key: s.split(/:|：/g)[0],\n      label: s.split(/:|：/g)[0],\n      placeholder: s.split(/:|：/g)[1] || '',\n    }));\n    return { ...lowcodeContext.model, formItems };\n  },\n  OCR: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    const res = await main.handleOCR();\n    return res;\n  },\n  runScript: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    const res = await main.handleRunScript();\n    return res;\n  },\n};\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Form 表单/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { CompileContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Form 表单/script/src/main.ts",
    "content": "import * as path from 'path';\nimport * as fs from 'fs-extra';\nimport { window } from 'vscode';\nimport { generalBasic } from '@share/BaiduOCR/index';\nimport { translate } from '@share/TypeChatSlim/index';\nimport { context } from './context';\nimport { IFormItems } from '../../config/schema';\n\nexport async function handleOCR() {\n  const { lowcodeContext } = context;\n  if (!lowcodeContext?.clipboardImage) {\n    window.showInformationMessage('剪贴板里没有截图');\n    return {\n      updateModelImmediately: false,\n      onlyUpdateParams: true,\n      params: '',\n      model: lowcodeContext?.model,\n    };\n  }\n  const ocrRes = await generalBasic({ image: lowcodeContext!.clipboardImage! });\n  return {\n    updateModelImmediately: false,\n    onlyUpdateParams: true,\n    params: ocrRes.words_result.map((s) => s.words).join('\\r\\n'),\n    model: lowcodeContext?.model,\n  };\n}\n\nconst scriptHandle: {\n  [method: string]: () => Promise<{\n    updateModelImmediately: boolean;\n    onlyUpdateParams: boolean;\n    params?: string;\n    model: any;\n  }>;\n} = {\n  askChatGPT: async () => {\n    const { lowcodeContext } = context;\n    const schema = fs.readFileSync(\n      path.join(lowcodeContext!.materialPath, 'config/schema.ts'),\n      'utf8',\n    );\n    const typeName = 'IFormItems';\n    const res = await translate<IFormItems>({\n      schema,\n      typeName,\n      request: JSON.stringify(\n        (lowcodeContext!.model as { formItems: IFormItems }).formItems,\n      ),\n      completePrompt:\n        `你是一个根据以下 TypeScript 类型定义将用户请求转换为 \"${typeName}\" 类型的 JSON 对象的服务，并且按照字段的注释进行处理:\\n` +\n        `\\`\\`\\`\\n${schema}\\`\\`\\`\\n` +\n        `以下是用户请求:\\n` +\n        `\"\"\"\\n${JSON.stringify(\n          (lowcodeContext!.model as { formItems: IFormItems }).formItems,\n        )}\\n\"\"\"\\n` +\n        `The following is the user request translated into a JSON object with 2 spaces of indentation and no properties with the value undefined:\\n`,\n      createChatCompletion: lowcodeContext!.createChatCompletion,\n      showWebview: true,\n      extendValidate: (jsonObject) => ({ success: true, data: jsonObject }),\n    });\n    lowcodeContext!.outputChannel.appendLine(JSON.stringify(res, null, 2));\n    if (res.success) {\n      return {\n        updateModelImmediately: false,\n        onlyUpdateParams: false,\n        params: '',\n        model: { ...lowcodeContext?.model, formItems: res.data },\n      };\n    }\n    return {\n      updateModelImmediately: false,\n      onlyUpdateParams: false,\n      params: '',\n      model: lowcodeContext?.model,\n    };\n  },\n};\n\nexport async function handleRunScript() {\n  const { lowcodeContext } = context;\n  const res = await scriptHandle[lowcodeContext!.method]();\n  return res;\n}\n\nexport async function handleComplete() {\n  const createBlockPath = context.lowcodeContext?.createBlockPath;\n  if (createBlockPath) {\n    // #region 更新 model.ts 文件\n    const modelFileContent = fs\n      .readFileSync(path.join(createBlockPath, 'temp.model.ts'))\n      .toString();\n    let modelFileContentOld = fs\n      .readFileSync(path.join(createBlockPath, 'model.ts'))\n      .toString();\n\n    const keywords = [\n      '// lowcode-model-type',\n      '// lowcode-model-defalut-data',\n      '// lowcode-model-variable',\n      '// lowcode-model-return-variable',\n    ];\n    const modelSplitArr = modelFileContent.split(\n      new RegExp(keywords.join('|'), 'ig'),\n    );\n    const modelType = modelSplitArr[1];\n    const modelDefaultData = modelSplitArr[2];\n    const modelVariable = modelSplitArr[3];\n    const modelReturnVariable = modelSplitArr[4].replace(/\\n/g, '');\n\n    if (!modelFileContentOld.includes('// lowcode-model-type')) {\n      modelFileContentOld = modelFileContentOld.replace(\n        'export const useModel',\n        '// lowcode-model-type\\nexport const useModel',\n      );\n    }\n    modelFileContentOld = modelFileContentOld.replace(\n      '// lowcode-model-type',\n      modelType,\n    );\n\n    if (!modelFileContentOld.includes('// lowcode-model-defalut-data')) {\n      modelFileContentOld = modelFileContentOld.replace(\n        'export const useModel',\n        '// lowcode-model-defalut-data\\nexport const useModel',\n      );\n    }\n    modelFileContentOld = modelFileContentOld.replace(\n      '// lowcode-model-defalut-data',\n      modelDefaultData,\n    );\n\n    if (!modelFileContentOld.includes('// lowcode-model-variable')) {\n      modelFileContentOld = modelFileContentOld.replace(\n        'return {',\n        '// lowcode-model-variable\\nreturn {',\n      );\n    }\n    modelFileContentOld = modelFileContentOld.replace(\n      '// lowcode-model-variable',\n      modelVariable,\n    );\n\n    if (!modelFileContentOld.includes('// lowcode-model-return-variable')) {\n      modelFileContentOld = modelFileContentOld.replace(\n        'return {',\n        'return {\\n// lowcode-model-return-variable',\n      );\n    }\n    modelFileContentOld = modelFileContentOld.replace(\n      '// lowcode-model-return-variable',\n      modelReturnVariable,\n    );\n\n    fs.writeFileSync(\n      path.join(createBlockPath, 'model.ts'),\n      modelFileContentOld,\n    );\n    fs.removeSync(path.join(createBlockPath, 'temp.model.ts'));\n    // #endregion\n\n    // #region 更新 service.ts 文件\n    const serviceFileContent = fs\n      .readFileSync(path.join(createBlockPath, 'temp.service.ts'))\n      .toString();\n    let serviceFileContentOld = fs\n      .readFileSync(path.join(createBlockPath, 'service.ts'))\n      .toString()\n      .trim();\n\n    const serviceSplitArr = serviceFileContent.split(\n      new RegExp(['// lowcode-service-method'].join('|'), 'ig'),\n    );\n    const serviceMethod = serviceSplitArr[1];\n    if (!serviceFileContentOld.includes('// lowcode-service-method')) {\n      serviceFileContentOld = `${serviceFileContentOld.slice(\n        0,\n        serviceFileContentOld.length - 1,\n      )}// lowcode-service-method\\n}`;\n    }\n    serviceFileContentOld = serviceFileContentOld.replace(\n      '// lowcode-service-method',\n      serviceMethod,\n    );\n    fs.writeFileSync(\n      path.join(createBlockPath, 'service.ts'),\n      serviceFileContentOld,\n    );\n    fs.removeSync(path.join(createBlockPath, 'temp.service.ts'));\n\n    // #endregion\n\n    // #region 更新 presenter 文件\n    const presenterFileContent = fs\n      .readFileSync(path.join(createBlockPath, 'temp.presenter.ts'))\n      .toString();\n\n    let presenterFile = path.join(createBlockPath, 'presenter.ts');\n    if (!fs.existsSync(presenterFile)) {\n      presenterFile = path.join(createBlockPath, 'presenter.tsx');\n    }\n    let presenterFileContentOld = fs.readFileSync(presenterFile).toString();\n\n    const presenterSplitArr = presenterFileContent.split(\n      new RegExp(\n        ['// lowcode-presenter-variable', '// lowcode-presenter-return'].join(\n          '|',\n        ),\n        'ig',\n      ),\n    );\n    const presenterVariable = presenterSplitArr[1];\n    const presenterReturn = presenterSplitArr[2];\n\n    if (!presenterFileContentOld.includes('// lowcode-presenter-variable')) {\n      presenterFileContentOld = presenterFileContentOld.replace(\n        'return {',\n        `// lowcode-presenter-variable\\nreturn {`,\n      );\n    }\n    presenterFileContentOld = presenterFileContentOld.replace(\n      '// lowcode-presenter-variable',\n      presenterVariable,\n    );\n\n    if (!presenterFileContentOld.includes('// lowcode-presenter-return')) {\n      presenterFileContentOld = presenterFileContentOld.replace(\n        'return {',\n        'return {\\n// lowcode-presenter-return',\n      );\n    }\n    presenterFileContentOld = presenterFileContentOld.replace(\n      '// lowcode-presenter-return',\n      presenterReturn,\n    );\n    fs.writeFileSync(presenterFile, presenterFileContentOld);\n    fs.removeSync(path.join(createBlockPath, 'temp.presenter.ts'));\n    // #endregion\n\n    // #region 更新 index.vue 文件\n    const vueFileContent = fs\n      .readFileSync(path.join(createBlockPath, 'temp.index.vue').toString())\n      .toString();\n\n    let vueFileContentOld = fs\n      .readFileSync(path.join(createBlockPath, 'index.vue').toString())\n      .toString();\n\n    const vueSplitArr = vueFileContent.split(\n      new RegExp(\n        ['<!-- lowcode-vue-template -->', '// lowcode-vue-import'].join('|'),\n        'ig',\n      ),\n    );\n    const vueTemplate = vueSplitArr[1];\n    const vueImport = vueSplitArr[2];\n\n    if (!vueFileContentOld.includes('<!-- lowcode-vue-template -->')) {\n      const index = vueFileContentOld.lastIndexOf('</template>');\n      vueFileContentOld = `${vueFileContentOld.substring(\n        0,\n        index,\n      )}<!-- lowcode-vue-template -->${vueFileContentOld.substring(index)}`;\n    }\n    vueFileContentOld = vueFileContentOld.replace(\n      '<!-- lowcode-vue-template -->',\n      vueTemplate,\n    );\n\n    if (!vueFileContentOld.includes('lowcode-vue-import')) {\n      vueFileContentOld = vueFileContentOld.replace(\n        '<script lang=\"ts\" setup>',\n        `<script lang=\"ts\" setup>\\n// lowcode-vue-import`,\n      );\n    }\n    vueFileContentOld = vueFileContentOld.replace(\n      '// lowcode-vue-import',\n      vueImport,\n    );\n\n    fs.writeFileSync(\n      path.join(createBlockPath, 'index.vue'),\n      vueFileContentOld,\n    );\n    fs.removeSync(path.join(createBlockPath, 'temp.index.vue'));\n    // #endregion\n  }\n}\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Form 表单/src/temp.index.vue.ejs",
    "content": "<!-- lowcode-vue-template -->\n<a-form :label-col=\"{ span: 4 }\" :wrapper-col=\"{ span: 12 }\">\n\t<% formItems.map(item => { _%>\n\t\t<% if(item.component === \"input\") { _%>\n\t\t\t<a-form-item\n\t\t\t\t<% if(item.label) { _%>\n\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t<% } _%>\n\t\t\t\tv-bind=\"presenter.validate<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Infos.<%= item.key %>\"\n\t\t\t>\n\t\t\t\t<a-input \n\t\t\t\t\tv-model:value=\"model.<%= variableName %>FormData.<%= item.key %>\" \n\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\tallow-clear\n\t\t\t\t\t<% if(item.maxlength) { _%>\n\t\t\t\t\t:maxlength=\"<%= item.maxlength %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.showCount) { _%>\n\t\t\t\t\tshowCount\n\t\t\t\t\t<% } _%>\n\t\t\t\t>\n\t\t\t\t</a-input>\n\t\t\t</a-form-item>\n\t\t<% } _%>\n\t\t<% if(item.component === \"input-password\") { _%>\n\t\t\t<a-form-item\n\t\t\t\t<% if(item.label) { _%>\n\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t<% } _%>\n\t\t\t\tv-bind=\"presenter.validate<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Infos.<%= item.key %>\"\n\t\t\t>\n\t\t\t\t<a-input-password\n\t\t\t\t\tv-model:value=\"model.<%= variableName %>FormData.<%= item.key %>\" \n\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\tallowClear\n\t\t\t\t\t<% if(item.maxlength) { _%>\n\t\t\t\t\t:maxlength=\"<%= item.maxlength %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.showCount) { _%>\n\t\t\t\t\tshowCount\n\t\t\t\t\t<% } _%>\n\t\t\t\t></a-input-password>\n\t\t\t</a-form-item>\n\t\t<% } _%>\n\t\t<% if(item.component === \"input-number\") { _%>\n\t\t\t<a-form-item\n\t\t\t\t<% if(item.label) { _%>\n\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t<% } _%>\n\t\t\t\tv-bind=\"presenter.validate<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Infos.<%= item.key %>\"\n\t\t\t>\n\t\t\t\t<a-input-number\n\t\t\t\t\tv-model:value=\"model.<%= variableName %>FormData.<%= item.key %>\"\n\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\tallowClear\n\t\t\t\t\t<% if(item.max) { _%>\n\t\t\t\t\t:max=\"<%= item.max %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.min) { _%>\n\t\t\t\t\t:min=\"<%= item.min %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.step) { _%>\n\t\t\t\t\t:step=\"<%= item.step %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t></a-input-number>\n\t\t\t</a-form-item>\n\t\t<% } _%>\n\t\t<% if(item.component === \"textarea\") { _%>\n\t\t\t<a-form-item\n\t\t\t\t<% if(item.label) { _%>\n\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t<% } _%>\n\t\t\t\tv-bind=\"presenter.validate<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Infos.<%= item.key %>\"\n\t\t\t>\n\t\t\t\t<a-textarea\n\t\t\t\t\tv-model:value=\"model.<%= variableName %>FormData.<%= item.key %>\" \n\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\tallow-clear\n\t\t\t\t\t<% if(item.maxlength) { _%>\n\t\t\t\t\t:maxlength=\"<%= item.maxlength %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.showCount) { _%>\n\t\t\t\t\tshowCount\n\t\t\t\t\t<% } _%>\n\t\t\t\t>\n\t\t\t\t</a-textarea>\n\t\t\t</a-form-item>\n\t\t<% } _%>\n\t\t<% if(item.component === \"select\") { _%>\n\t\t\t<a-form-item \n\t\t\t\t<% if(item.label) { _%>\n\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t<% } _%> \n\t\t\t\tv-bind=\"presenter.validate<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Infos.<%= item.key %>\"\n\t\t\t>\n\t\t\t\t<a-select\n\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\tallow-clear\n\t\t\t\t\t:options=\"model.options.<%= item.key %>\"\n\t\t\t\t\tv-model:value=\"model.<%= variableName %>FormData.<%= item.key %>\"\n\t\t\t\t\t<% if(item.labelInValue) { _%>\n\t\t\t\t\tlabelInValue\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.mode) { _%>\n\t\t\t\t\tmode=\"<%= item.mode %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t\toptionFilterProp=\"<%= item.optionFilterProp || 'label' %>\"\n\t\t\t\t\t<% if(item.showSearch) { _%>\n\t\t\t\t\tshowSearch\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.hideArrow) { _%>\n\t\t\t\t\t:showArrow=\"false\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t></a-select>\n\t\t\t</a-form-item>\n\t\t<% } _%>\n\t\t<% if(item.component === \"radio-group\") { _%>\n\t\t\t<a-form-item \n\t\t\t\t<% if(item.label) { _%>\n\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t<% } _%>\n\t\t\t\tv-bind=\"presenter.validate<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Infos.<%= item.key %>\"\n\t\t\t>\n\t\t\t\t<a-radio-group v-model:value=\"model.<%= variableName %>FormData.<%= item.key %>\">\n\t\t\t\t\t<a-radio\n\t\t\t\t\t\tv-for=\"item in model.options.<%= item.key %>\"\n\t\t\t\t\t\t:value=\"item.value\"\n\t\t\t\t\t\t:key=\"item.value\"\n\t\t\t\t\t\t>{{ item.label }}\n\t\t\t\t\t</a-radio>\n\t\t\t\t</a-radio-group>\n\t\t\t</a-form-item>\n\t\t<% } _%>\n\t\t<% if(item.component === \"checkbox-group\") { _%>\n\t\t\t<a-form-item \n\t\t\t\t<% if(item.label) { _%>\n\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t<% } _%>\n\t\t\t\tv-bind=\"presenter.validate<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Infos.<%= item.key %>\"\n\t\t\t>\n\t\t\t\t<a-checkbox-group\n\t\t\t\t\tv-model:value=\"model.<%= variableName %>FormData.<%= item.key %>\"\n\t\t\t\t\tstyle=\"width: 100%; margin-top: 6px\"\n\t\t\t\t>\n\t\t\t\t\t<a-row>\n\t\t\t\t\t<a-col\n\t\t\t\t\t\t:span=\"8\"\n\t\t\t\t\t\tv-for=\"item in model.options.<%= item.key %>\"\n\t\t\t\t\t\t:key=\"item.value\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<a-checkbox :value=\"item.value\">{{ item.label }} </a-checkbox>\n\t\t\t\t\t</a-col>\n\t\t\t\t\t</a-row>\n\t\t\t\t</a-checkbox-group>\n\t\t\t</a-form-item>\n\t\t<% } _%>\n\t\t<% if(item.component === \"switch\") { _%>\n\t\t\t<a-form-item \n\t\t\t\t<% if(item.label) { _%>\n\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t<% } _%> \n\t\t\t\tv-bind=\"presenter.validate<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Infos.<%= item.key %>\"\n\t\t\t>\n\t\t\t\t<a-switch\n\t\t\t\t\tv-model:checked=\"model.<%= variableName %>FormData.<%= item.key %>\"\n\t\t\t\t\t<% if(item.checkedChildren) { _%>\n\t\t\t\t\tcheckedChildren=\"<%= item.checkedChildren %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.unCheckedChildren) { _%>\n\t\t\t\t\tunCheckedChildren=\"<%= item.unCheckedChildren %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.checkedValue) { _%>\n\t\t\t\t\t\tcheckedValue=\"<%= item.checkedValue || 'true' %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<% if(item.unCheckedValue) { _%>\n\t\t\t\t\t\tunCheckedValue=\"<%= item.unCheckedValue || 'false' %>\"\n\t\t\t\t\t<% } _%>\n\t\t\t\t></a-switch>\n\t\t\t</a-form-item>\n\t\t<% } _%>\n\t\t<% if(item.component === \"date-picker\") { _%>\n\t\t\t<a-form-item \n\t\t\t\t<% if(item.label) { _%>\n\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t<% } _%> \n\t\t\t\tv-bind=\"presenter.validate<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Infos.<%= item.key %>\"\n\t\t\t>\n\t\t\t\t<a-date-picker\n\t\t\t\t\tv-model:value=\"model.<%= variableName %>FormData.<%= item.key %>\"\n\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\tallow-clear\n\t\t\t\t\tpicker=\"<%= item.picker || 'date' %>\"\n\t\t\t\t\t:showTime=\"<%= item.showTime || false %>\"\n\t\t\t\t\t:showNow=\"<%= item.showNow || false %>\"\n\t\t\t\t\t:showToday=\"<%= item.showToday || false %>\"\n\t\t\t\t/>\n\t\t\t</a-form-item>\n\t\t<% } _%>\n\t\t<% if(item.component === \"range-picker\") { _%>\n\t\t\t<a-form-item \n\t\t\t\t<% if(item.label) { _%>\n\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t<% } _%> \n\t\t\t\tv-bind=\"presenter.validate<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Infos.<%= item.key %>\"\n\t\t\t>\n\t\t\t\t<a-range-picker\n\t\t\t\t\tv-model:value=\"model.<%= variableName %>FormData.<%= item.key %>\"\n\t\t\t\t\t:placeholder=\"['<%- item.placeholder || '\\'\\'' %>','<%- item.placeholder || '\\'\\'' %>']\"\n\t\t\t\t\tallow-clear\n\t\t\t\t\tpicker=\"<%= item.picker || 'date' %>\"\n\t\t\t\t\t:showTime=\"<%= item.showTime || false %>\"\n\t\t\t\t\t:showNow=\"<%= item.showNow || false %>\"\n\t\t\t\t\t:showToday=\"<%= item.showToday || false %>\"\n\t\t\t\t/>\n\t\t\t</a-form-item>\n\t\t<% } _%>\n\t\t<% if(item.component === \"time-picker\") { _%>\n\t\t\t<a-form-item \n\t\t\t\t<% if(item.label) { _%>\n\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t<% } _%> \n\t\t\t\tv-bind=\"presenter.validate<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Infos.<%= item.key %>\"\n\t\t\t>\n\t\t\t\t<a-time-picker\n\t\t\t\t\tv-model:value=\"model.<%= variableName %>FormData.<%= item.key %>\"\n\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\tallow-clear\n\t\t\t\t/>\n\t\t\t</a-form-item>\n\t\t<% } _%>\n\t\t<% if(item.component === \"uploadFiles\") { _%>\n\t\t\t<a-form-item \n\t\t\t\t<% if(item.label) { _%>\n\t\t\t\tlabel=\"<%= item.label %>\"\n\t\t\t\t<% } _%> \n\t\t\t\tv-bind=\"presenter.validate<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Infos.<%= item.key %>\"\n\t\t\t>\n\t\t\t\t<upload-files\n\t\t\t\t\tv-model:values=\"model.<%= variableName %>FormData.<%= item.key %>\"\n\t\t\t\t\tlistType=\"picture-card\"\n\t\t\t\t\tformatLimit=\"jpg,png\"\n\t\t\t\t/>\n\t\t\t</a-form-item>\n\t\t<% } _%>\n\t<% }) _%>\n</a-form>\n// lowcode-vue-import\n<% if(formItems.some(s => s.component === \"uploadFiles\")){ _%>\nimport UploadFiles from '@/components/UploadFiles/index.vue';\n<% } _%>\n\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Form 表单/src/temp.model.ts.ejs",
    "content": "// lowcode-model-type\nexport interface I<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>FormData {\n\t<% formItems.map(item => { _%>\n\t\t/** <%= item.label %> */\n\t\t<%= item.key %><% if(item.optional){ _%>?<% } _%>: <%= item.type %>;\n\t<% }) _%>\n}\n\n<% if(formItems.some(s => s.component === \"select\" || s.component === \"radio-group\" || s.component === 'checkbox-group')){ %>\n\tinterface I<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>FormOptionItem {\n\t\tlabel: string;\n\t\tvalue: string;\n\t}\n\t\ninterface I<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>FormOptions {\n\t<% formItems.filter(s => s.component === \"select\" || s.component === \"radio-group\" || s.component === 'checkbox-group').map(item => { _%>\n\t\t<%= item.key %>: I<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>FormOptionItem[];\n\t<% }) _%>\n}\n<% } %>\n\n// lowcode-model-defalut-data\nconst default<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>FormData: I<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>FormData = {\n\t<% formItems.map(item => { _%>\n\t\t<%= item.key %>: <%- item.defaultValue || '\\\"\\\"' %>,\n\t<% }) _%>\n};\n<% if(formItems.some(s => s.component === \"select\" || s.component === \"radio-group\" || s.component === 'checkbox-group')){ %>\nconst default<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>FormOptions: I<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>FormOptions = {\n  <% formItems.filter(s => s.component === \"select\" || s.component === \"radio-group\" || s.component === 'checkbox-group').map(item => { _%>\n\t\t<%= item.key %>: [],\n\t<% }) _%>\n};\n<% } %>\n\n// lowcode-model-variable\nconst <%= variableName %>FormData = reactive<I<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>FormData>({ ...default<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>FormData });\n<% if(formItems.some(s => s.component === \"select\" || s.component === \"radio-group\" || s.component === 'checkbox-group')){ _%>\nconst <%= variableName %>FormOptions = reactive<I<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>FormOptions>({ ...default<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>FormOptions });\n<% } _%>\n\n// lowcode-model-return-variable\n<%= variableName %>FormData, \n<% if(formItems.some(s => s.component === \"select\" || s.component === \"radio-group\" || s.component === 'checkbox-group')){ _%>\n<%= variableName %>FormOptions,\n<% } _%>\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Form 表单/src/temp.presenter.ts.ejs",
    "content": "// lowcode-presenter-variable\nconst <%= variableName %>Rules: Record<string, Rule[]> = reactive({\n\t<% formItems.map(item => { _%>\n\t\t<%= item.key %>: [{ required: <%= item.required || false %>, message: \"<%= item.message %>\" }],\n\t<% }) _%>\n});\n\nconst { resetFields: reset<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Fields, validate: validate<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>, validateInfos: validate<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Infos } = useForm(\n\tmodel.<%= variableName %>FormData,\n\t<%= variableName %>Rules,\n);\n\n// lowcode-presenter-return\nvalidate<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Infos,\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Form 表单/src/temp.service.ts.ejs",
    "content": "// lowcode-service-method\nasync submit<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>() {\n\tconst data = {\n\t\t<% formItems.map(item => { _%>\n\t\t\t<%= item.key %>: this.model.<%= variableName %>FormData.<%= item.key %>,\n\t\t<% }) _%>\n\t};\n\tawait Promise.resolve(data);\n}\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Modal 弹框/config/model.json",
    "content": "{\n\t\"variableName\": \"\",\n\t\"title\": \"\"\n}"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Modal 弹框/config/preview.json",
    "content": "{\n\t\"title\": \"\",\n\t\"description\": \"\",\n\t\"img\": [\n\t\t\"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n\t],\n\t\"category\": [],\n\t\"schema\": \"amis\",\n\t\"scripts\": []\n}"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Modal 弹框/config/schema.json",
    "content": "{\n\t\"type\": \"page\",\n\t\"body\": [\n\t\t{\n\t\t\t\"type\": \"form\",\n\t\t\t\"title\": \"\",\n\t\t\t\"body\": [\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\"label\": \"变量名\",\n\t\t\t\t\t\"name\": \"variableName\",\n\t\t\t\t\t\"id\": \"u:2b8da51d12fc\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\"label\": \"title\",\n\t\t\t\t\t\"name\": \"title\"\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"submitText\": \"\",\n\t\t\t\"id\": \"u:b3438715e11f\"\n\t\t}\n\t],\n\t\"pullRefresh\": {\n\t\t\"disabled\": true\n\t},\n\t\"regions\": [\n\t\t\"body\"\n\t],\n\t\"style\": {\n\t\t\"boxShadow\": \" 0px 0px 0px 0px transparent\"\n\t},\n\t\"asideResizor\": false,\n\t\"id\": \"u:87ed78162ffc\"\n}"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Modal 弹框/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/blocks/现有模块中添加 antdv Modal 弹框/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/blocks/现有模块中添加 antdv Modal 弹框/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: (lowcodeContext) => {},\n  complete: (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    main.handleComplete();\n  },\n};\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Modal 弹框/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { ViewCallContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: ViewCallContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Modal 弹框/script/src/main.ts",
    "content": "import * as path from 'path';\nimport * as fs from 'fs-extra';\nimport * as execa from 'execa';\nimport { workspace } from 'vscode';\nimport { context } from './context';\n\nexport async function handleComplete() {\n  const createBlockPath = context.lowcodeContext?.createBlockPath;\n  if (createBlockPath) {\n    // #region 更新 model.ts 文件\n    const modelFileContent = fs\n      .readFileSync(path.join(createBlockPath, 'temp.model.ts'))\n      .toString();\n    let modelFileContentOld = fs\n      .readFileSync(path.join(createBlockPath, 'model.ts').toString())\n      .toString();\n\n    const keywords = [\n      '// lowcode-model-variable',\n      '// lowcode-model-return-variable',\n    ];\n    const modelSplitArr = modelFileContent.split(\n      new RegExp(keywords.join('|'), 'ig'),\n    );\n\n    const modelVariable = modelSplitArr[1];\n    const modelReturnVariable = modelSplitArr[2].replace(/\\n/g, '');\n\n    if (!modelFileContentOld.includes('// lowcode-model-variable')) {\n      modelFileContentOld = modelFileContentOld.replace(\n        'return {',\n        '// lowcode-model-variable\\nreturn {',\n      );\n    }\n    modelFileContentOld = modelFileContentOld.replace(\n      '// lowcode-model-variable',\n      modelVariable,\n    );\n\n    if (!modelFileContentOld.includes('// lowcode-model-return-variable')) {\n      modelFileContentOld = modelFileContentOld.replace(\n        'return {',\n        'return {\\n// lowcode-model-return-variable',\n      );\n    }\n    modelFileContentOld = modelFileContentOld.replace(\n      '// lowcode-model-return-variable',\n      modelReturnVariable,\n    );\n\n    fs.writeFileSync(\n      path.join(createBlockPath, 'model.ts'),\n      modelFileContentOld,\n    );\n    fs.removeSync(path.join(createBlockPath, 'temp.model.ts'));\n    try {\n      execa.sync('node', [\n        path.join(workspace.rootPath!, '/node_modules/eslint/bin/eslint.js'),\n        path.join(createBlockPath, 'model.ts'),\n        '--resolve-plugins-relative-to',\n        workspace.rootPath!,\n        '--fix',\n      ]);\n    } catch (err) {\n      console.log(err);\n    }\n    // #endregion\n\n    // #region 更新 presenter 文件\n    const presenterFileContent = fs\n      .readFileSync(path.join(createBlockPath, 'temp.presenter.ts'))\n      .toString();\n\n    let presenterFile = path.join(createBlockPath, 'presenter.ts');\n    if (!fs.existsSync(presenterFile)) {\n      presenterFile = path.join(createBlockPath, 'presenter.tsx');\n    }\n    let presenterFileContentOld = fs.readFileSync(presenterFile).toString();\n\n    const presenterSplitArr = presenterFileContent.split(\n      new RegExp(\n        [\n          '// lowcode-presenter-handle',\n          '// lowcode-presenter-return-handle',\n        ].join('|'),\n        'ig',\n      ),\n    );\n    const presenterMethod = presenterSplitArr[1];\n    const presenterReturnMethod = presenterSplitArr[2];\n\n    if (!presenterFileContentOld.includes('// lowcode-presenter-handle')) {\n      presenterFileContentOld = presenterFileContentOld.replace(\n        'return {',\n        `// lowcode-presenter-handle\\nreturn {`,\n      );\n    }\n    presenterFileContentOld = presenterFileContentOld.replace(\n      '// lowcode-presenter-handle',\n      presenterMethod,\n    );\n\n    if (\n      !presenterFileContentOld.includes('// lowcode-presenter-return-handle')\n    ) {\n      presenterFileContentOld = presenterFileContentOld.replace(\n        'return {',\n        'return {\\n// lowcode-presenter-return-handle',\n      );\n    }\n    presenterFileContentOld = presenterFileContentOld.replace(\n      '// lowcode-presenter-return-handle',\n      presenterReturnMethod,\n    );\n    fs.writeFileSync(presenterFile, presenterFileContentOld);\n    fs.removeSync(path.join(createBlockPath, 'temp.presenter.ts'));\n    try {\n      execa.sync('node', [\n        path.join(workspace.rootPath!, '/node_modules/eslint/bin/eslint.js'),\n        presenterFile,\n        '--resolve-plugins-relative-to',\n        workspace.rootPath!,\n        '--fix',\n      ]);\n    } catch (err) {\n      console.log(err);\n    }\n    // #endregion\n\n    // #region 更新 index.vue 文件\n    const vueFileContent = fs\n      .readFileSync(path.join(createBlockPath, 'temp.index.vue').toString())\n      .toString();\n\n    let vueFileContentOld = fs\n      .readFileSync(path.join(createBlockPath, 'index.vue').toString())\n      .toString();\n\n    const vueSplitArr = vueFileContent.split(\n      new RegExp(['<!-- lowcode-vue-template -->'].join('|'), 'ig'),\n    );\n    const vueTemplate = vueSplitArr[1];\n\n    if (!vueFileContentOld.includes('<!-- lowcode-vue-template -->')) {\n      const index = vueFileContentOld.lastIndexOf('</template>');\n      vueFileContentOld = `${vueFileContentOld.substring(\n        0,\n        index,\n      )}<!-- lowcode-vue-template -->${vueFileContentOld.substring(index)}`;\n    }\n    vueFileContentOld = vueFileContentOld.replace(\n      '<!-- lowcode-vue-template -->',\n      vueTemplate,\n    );\n\n    fs.writeFileSync(\n      path.join(createBlockPath, 'index.vue'),\n      vueFileContentOld,\n    );\n    fs.removeSync(path.join(createBlockPath, 'temp.index.vue'));\n    try {\n      execa.sync('node', [\n        path.join(workspace.rootPath!, '/node_modules/eslint/bin/eslint.js'),\n        path.join(createBlockPath, 'index.vue'),\n        '--resolve-plugins-relative-to',\n        workspace.rootPath!,\n        '--fix',\n      ]);\n    } catch (err) {\n      console.log(err);\n    }\n    // #endregion\n  }\n}\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Modal 弹框/src/temp.index.vue.ejs",
    "content": "<!-- lowcode-vue-template -->\n<a-modal\n\ttitle=\"<%= title %>\"\n\t:visible=\"model.<%= variableName %>Modal.visible\"\n\t:confirm-loading=\"model.<%= variableName %>Modal.loading\"\n\t@cancel=\"presenter.handleToggle<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>ModalVisible(false)\"\n\t@ok=\"presenter.handle<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>ModalOk\"\n>\n\tmodal\n</a-modal>\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Modal 弹框/src/temp.model.ts.ejs",
    "content": "// lowcode-model-variable\nconst <%= variableName %>Modal = reactive<{ visible: boolean; loading: boolean }>({\n\tvisible: false,\n\tloading: false,\n});\n// lowcode-model-return-variable\n<%= variableName %>Modal,\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Modal 弹框/src/temp.presenter.ts.ejs",
    "content": "// lowcode-presenter-handle\nconst handleToggle<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>ModalVisible = (visible: boolean) => {\n\tif (visible) {\n\t\tmodel.<%= variableName %>Modal.visible = true;\n\t} else {\n\t\tmodel.<%= variableName %>Modal.visible = false;\n\t}\n};\n\nconst handle<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>ModalOk = () => {\n\tmodel.<%= variableName %>Modal.visible = false;\n};\n// lowcode-presenter-return-handle\nhandleToggle<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>ModalVisible,\nhandle<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>ModalOk,\n\t"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Table 表格/config/model.json",
    "content": "{\n\t\"pagination\": {\n\t\t\"show\": true,\n\t\t\"page\": \"page\",\n\t\t\"size\": \"size\",\n\t\t\"total\": \"result.total\"\n\t},\n\t\"result\": \"[\\\"result\\\"][\\\"records\\\"]\",\n\t\"variableName\": \"\",\n\t\"columns\": []\n}"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Table 表格/config/preview.json",
    "content": "{\n\t\"title\": \"\",\n\t\"description\": \"\",\n\t\"img\": [\n\t\t\"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n\t],\n\t\"category\": [\n\t\t\"antd\",\n\t\t\"vue\",\n\t\t\"table\"\n\t],\n\t\"schema\": \"amis\",\n\t\"scripts\": [\n\t\t{\n\t\t\t\"method\": \"OCR\",\n\t\t\t\"remark\": \"OCR 识别剪贴版截图\"\n\t\t},\n\t\t{\n\t\t\t\"method\": \"intColumnsFromOcrText\",\n\t\t\t\"remark\": \"使用 ocr 结果初始化表格\"\n\t\t},\n\t\t{\n\t\t\t\"method\": \"askChatGPT\",\n\t\t\t\"remark\": \"使用 ChatGPT 翻译模版数据里的指定中文字段\"\n\t\t},\n\t\t{\n\t\t\t\"method\": \"intColumnsFromClipboardImage\",\n\t\t\t\"remark\": \"读取剪贴板截图并翻译，初始化列表\"\n\t\t}\n\t]\n}"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Table 表格/config/schema.json",
    "content": "{\n\t\"formSchema\": {\n\t\t\"schema\": {\n\t\t\t\"type\": \"page\",\n\t\t\t\"body\": [\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"form\",\n\t\t\t\t\t\"title\": \"\",\n\t\t\t\t\t\"body\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"label\": \"变量名\",\n\t\t\t\t\t\t\t\"name\": \"variableName\",\n\t\t\t\t\t\t\t\"id\": \"u:2b8da51d12fc\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"combo\",\n\t\t\t\t\t\t\t\"id\": \"u:9b9fb0cf38f9\",\n\t\t\t\t\t\t\t\"label\": \"表格\",\n\t\t\t\t\t\t\t\"name\": \"columns\",\n\t\t\t\t\t\t\t\"multiple\": true,\n\t\t\t\t\t\t\t\"addable\": true,\n\t\t\t\t\t\t\t\"removable\": true,\n\t\t\t\t\t\t\t\"removableMode\": \"button\",\n\t\t\t\t\t\t\t\"addBtn\": {\n\t\t\t\t\t\t\t\t\"label\": \"新增\",\n\t\t\t\t\t\t\t\t\"icon\": \"fa fa-plus\",\n\t\t\t\t\t\t\t\t\"level\": \"primary\",\n\t\t\t\t\t\t\t\t\"size\": \"sm\",\n\t\t\t\t\t\t\t\t\"id\": \"u:1e8070edc3d3\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"items\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"title\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:152dd82b82f9\",\n\t\t\t\t\t\t\t\t\t\"label\": \"title\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"dataIndex\",\n\t\t\t\t\t\t\t\t\t\"name\": \"dataIndex\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:ecc7298e0550\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"key\",\n\t\t\t\t\t\t\t\t\t\"name\": \"key\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:fbaa95c3f15d\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"width\",\n\t\t\t\t\t\t\t\t\t\"name\": \"width\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:b143127e097b\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"自定义插槽\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"slot\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:ee1ce1faee0b\",\n\t\t\t\t\t\t\t\t\t\"value\": false\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"strictMode\": true,\n\t\t\t\t\t\t\t\"syncFields\": [],\n\t\t\t\t\t\t\t\"tabsMode\": true,\n\t\t\t\t\t\t\t\"draggable\": true,\n\t\t\t\t\t\t\t\"draggableTip\": \"可拖动排序\",\n\t\t\t\t\t\t\t\"tabsStyle\": \"line\",\n\t\t\t\t\t\t\t\"deleteBtn\": {\n\t\t\t\t\t\t\t\t\"label\": \"删除\",\n\t\t\t\t\t\t\t\t\"level\": \"default\",\n\t\t\t\t\t\t\t\t\"id\": \"u:99b03ead4f4a\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"tabsLabelTpl\": \"列${index+1}\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"fieldset\",\n\t\t\t\t\t\t\t\"title\": \"分页参数\",\n\t\t\t\t\t\t\t\"collapsable\": true,\n\t\t\t\t\t\t\t\"body\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"是否分页\",\n\t\t\t\t\t\t\t\t\t\"name\": \"pagination.show\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:6c70041d5143\",\n\t\t\t\t\t\t\t\t\t\"value\": true,\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"className\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"查询接口页数参数字段名\",\n\t\t\t\t\t\t\t\t\t\"name\": \"pagination.page\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:cbbf6853cf64\",\n\t\t\t\t\t\t\t\t\t\"value\": \"page\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"查询接口每页数据行数参数字段名\",\n\t\t\t\t\t\t\t\t\t\"name\": \"pagination.size\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:a8fae66fa927\",\n\t\t\t\t\t\t\t\t\t\"value\": \"size\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"接口返回总数据量字段 PATH\",\n\t\t\t\t\t\t\t\t\t\"name\": \"pagination.total\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:e1cd979c7ee8\",\n\t\t\t\t\t\t\t\t\t\"value\": \"result.total\",\n\t\t\t\t\t\t\t\t\t\"themeCss\": {\n\t\t\t\t\t\t\t\t\t\t\"inputControlClassName\": {\n\t\t\t\t\t\t\t\t\t\t\t\"padding-and-margin:default\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"marginBottom\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"marginTop\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"marginRight\": \"\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"marginLeft\": \"\"\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"id\": \"u:0f1bd8fc2f2b\",\n\t\t\t\t\t\t\t\"collapsed\": false,\n\t\t\t\t\t\t\t\"headingClassName\": \"\",\n\t\t\t\t\t\t\t\"bodyClassName\": \"p\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"fieldset\",\n\t\t\t\t\t\t\t\"id\": \"u:382f8cdf59a6\",\n\t\t\t\t\t\t\t\"title\": \"请求方法\",\n\t\t\t\t\t\t\t\"collapsable\": true,\n\t\t\t\t\t\t\t\"body\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"label\": \"接口数据字段 PATH\",\n\t\t\t\t\t\t\t\t\t\"name\": \"result\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:8c082acf7db2\",\n\t\t\t\t\t\t\t\t\t\"value\": \"[\\\"result\\\"][\\\"records\\\"]\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"collapsed\": false,\n\t\t\t\t\t\t\t\"className\": \"\",\n\t\t\t\t\t\t\t\"headingClassName\": \"\",\n\t\t\t\t\t\t\t\"bodyClassName\": \"p-r p-l p-b\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"fieldset\",\n\t\t\t\t\t\t\t\"title\": \"占位符\",\n\t\t\t\t\t\t\t\"collapsable\": true,\n\t\t\t\t\t\t\t\"body\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"button-group\",\n\t\t\t\t\t\t\t\t\t\"buttons\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"button\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"插入 // lowcode-model-import-api\",\n\t\t\t\t\t\t\t\t\t\t\t\"onEvent\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"click\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"actions\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"actionType\": \"runScript\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"args\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"method\": \"insertPlaceholder\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"params\": \"// lowcode-model-import-api\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\"className\": \"max-w-full\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"button\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"复制\",\n\t\t\t\t\t\t\t\t\t\t\t\"onEvent\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"click\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"actions\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"actionType\": \"copy\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"args\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"copyFormat\": \"text/plain\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"content\": \"// lowcode-model-import-api\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\"className\": \"max-w-full\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"tiled\": true\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"button-group\",\n\t\t\t\t\t\t\t\t\t\"buttons\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"button\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"插入 // lowcode-model-import-api\",\n\t\t\t\t\t\t\t\t\t\t\t\"onEvent\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"click\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"actions\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"actionType\": \"runScript\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"args\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"method\": \"insertPlaceholder\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"params\": \"// lowcode-model-import-api\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"button\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"复制\",\n\t\t\t\t\t\t\t\t\t\t\t\"onEvent\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"click\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"actions\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"actionType\": \"copy\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"args\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"copyFormat\": \"text/plain\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"content\": \"// lowcode-model-import-api\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"tiled\": true,\n\t\t\t\t\t\t\t\t\t\"className\": \"m-t-xs\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"button-group\",\n\t\t\t\t\t\t\t\t\t\"buttons\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"button\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"插入 // lowcode-model-type\",\n\t\t\t\t\t\t\t\t\t\t\t\"onEvent\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"click\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"actions\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"actionType\": \"runScript\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"args\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"method\": \"insertPlaceholder\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"params\": \"// lowcode-model-type\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"button\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"复制\",\n\t\t\t\t\t\t\t\t\t\t\t\"onEvent\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"click\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"actions\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"actionType\": \"copy\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"args\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"copyFormat\": \"text/plain\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"content\": \"// lowcode-model-type\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"tiled\": true,\n\t\t\t\t\t\t\t\t\t\"className\": \"m-t-xs\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"button-group\",\n\t\t\t\t\t\t\t\t\t\"buttons\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"button\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"插入 // lowcode-model-variable\",\n\t\t\t\t\t\t\t\t\t\t\t\"onEvent\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"click\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"actions\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"actionType\": \"runScript\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"args\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"method\": \"insertPlaceholder\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"params\": \"// lowcode-model-variable\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"button\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"复制\",\n\t\t\t\t\t\t\t\t\t\t\t\"onEvent\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"click\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"actions\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"actionType\": \"copy\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"args\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"copyFormat\": \"text/plain\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"content\": \"// lowcode-model-variable\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"tiled\": true,\n\t\t\t\t\t\t\t\t\t\"className\": \"m-t-xs\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"button-group\",\n\t\t\t\t\t\t\t\t\t\"buttons\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"button\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"插入 // lowcode-model-return-variable\",\n\t\t\t\t\t\t\t\t\t\t\t\"onEvent\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"click\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"actions\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"actionType\": \"runScript\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"args\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"method\": \"insertPlaceholder\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"params\": \"// lowcode-model-return-variable\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"button\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"复制\",\n\t\t\t\t\t\t\t\t\t\t\t\"onEvent\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"click\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"actions\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"actionType\": \"copy\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"args\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"copyFormat\": \"text/plain\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"content\": \"// lowcode-model-return-variable\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"tiled\": true,\n\t\t\t\t\t\t\t\t\t\"className\": \"m-t-xs\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"button-group\",\n\t\t\t\t\t\t\t\t\t\"buttons\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"button\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"插入 // lowcode-service-import-api\",\n\t\t\t\t\t\t\t\t\t\t\t\"onEvent\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"click\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"actions\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"actionType\": \"runScript\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"args\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"method\": \"insertPlaceholder\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"params\": \"// lowcode-service-import-api\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"button\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"复制\",\n\t\t\t\t\t\t\t\t\t\t\t\"onEvent\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"click\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"actions\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"actionType\": \"copy\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"args\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"copyFormat\": \"text/plain\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"content\": \"// lowcode-service-import-api\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"tiled\": true,\n\t\t\t\t\t\t\t\t\t\"className\": \"m-t-md\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"button-group\",\n\t\t\t\t\t\t\t\t\t\"buttons\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"button\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"插入 // lowcode-service-method\",\n\t\t\t\t\t\t\t\t\t\t\t\"onEvent\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"click\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"actions\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"actionType\": \"runScript\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"args\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"method\": \"insertPlaceholder\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"params\": \"// lowcode-service-method\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"button\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"复制\",\n\t\t\t\t\t\t\t\t\t\t\t\"onEvent\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"click\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"actions\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"actionType\": \"copy\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"args\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"copyFormat\": \"text/plain\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"content\": \"// lowcode-service-method\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"tiled\": true,\n\t\t\t\t\t\t\t\t\t\"className\": \"m-t-xs\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"button-group\",\n\t\t\t\t\t\t\t\t\t\"buttons\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"button\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"插入 // lowcode-presenter-handlePageChange\",\n\t\t\t\t\t\t\t\t\t\t\t\"onEvent\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"click\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"actions\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"actionType\": \"runScript\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"args\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"method\": \"insertPlaceholder\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"params\": \"// lowcode-presenter-handlePageChange\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"button\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"复制\",\n\t\t\t\t\t\t\t\t\t\t\t\"onEvent\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"click\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"actions\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"actionType\": \"copy\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"args\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"copyFormat\": \"text/plain\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"content\": \"// lowcode-presenter-handlePageChange\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"tiled\": true,\n\t\t\t\t\t\t\t\t\t\"className\": \"m-t-md\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"button-group\",\n\t\t\t\t\t\t\t\t\t\"buttons\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"button\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"插入 // lowcode-presenter-return-handlePageChange\",\n\t\t\t\t\t\t\t\t\t\t\t\"onEvent\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"click\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"actions\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"actionType\": \"runScript\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"args\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"method\": \"insertPlaceholder\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"params\": \"// lowcode-presenter-return-handlePageChange\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"button\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"复制\",\n\t\t\t\t\t\t\t\t\t\t\t\"onEvent\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"click\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"actions\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"actionType\": \"copy\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"args\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"copyFormat\": \"text/plain\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"content\": \"// lowcode-presenter-return-handlePageChange\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"tiled\": true,\n\t\t\t\t\t\t\t\t\t\"className\": \"m-t-xs\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"button-group\",\n\t\t\t\t\t\t\t\t\t\"buttons\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"button\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"插入 <!-- lowcode-vue-template -->\",\n\t\t\t\t\t\t\t\t\t\t\t\"onEvent\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"click\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"actions\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"actionType\": \"runScript\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"args\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"method\": \"insertPlaceholder\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"params\": \"<!-- lowcode-vue-template -->\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"button\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"复制\",\n\t\t\t\t\t\t\t\t\t\t\t\"onEvent\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"click\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"actions\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"actionType\": \"copy\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"args\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"copyFormat\": \"text/plain\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"content\": \"<!-- lowcode-vue-template -->\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"tiled\": true,\n\t\t\t\t\t\t\t\t\t\"className\": \"m-t-md\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"button-group\",\n\t\t\t\t\t\t\t\t\t\"buttons\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"button\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"插入 // lowcode-vue-columns\",\n\t\t\t\t\t\t\t\t\t\t\t\"onEvent\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"click\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"actions\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"actionType\": \"runScript\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"args\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"method\": \"insertPlaceholder\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"params\": \"// lowcode-vue-columns\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"button\",\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"复制\",\n\t\t\t\t\t\t\t\t\t\t\t\"onEvent\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"click\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"actions\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"actionType\": \"copy\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"args\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"copyFormat\": \"text/plain\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"content\": \"// lowcode-vue-columns\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"tiled\": true,\n\t\t\t\t\t\t\t\t\t\"className\": \"m-t-xs\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"collapsed\": true,\n\t\t\t\t\t\t\t\"className\": \"\",\n\t\t\t\t\t\t\t\"headingClassName\": \"\",\n\t\t\t\t\t\t\t\"bodyClassName\": \"p-r p-l p-b\"\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\t\"submitText\": \"\",\n\t\t\t\t\t\"id\": \"u:b3438715e11f\"\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"pullRefresh\": {\n\t\t\t\t\"disabled\": true\n\t\t\t},\n\t\t\t\"regions\": [\n\t\t\t\t\"body\"\n\t\t\t],\n\t\t\t\"style\": {\n\t\t\t\t\"boxShadow\": \" 0px 0px 0px 0px transparent\"\n\t\t\t},\n\t\t\t\"asideResizor\": false,\n\t\t\t\"id\": \"u:87ed78162ffc\"\n\t\t}\n\t},\n\t\"conditionFiles\": {\n\t\t\"name\": {\n\t\t\t\"value\": \"123\",\n\t\t\t\"exclude\": [\n\t\t\t\t\"当表单name的值为123,删除这个数组里的文件.ejs\"\n\t\t\t]\n\t\t}\n\t},\n\t\"excludeCompile\": [\n\t\t\"temp.mock.script.ejs\"\n\t]\n}"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Table 表格/config/schema.ts",
    "content": "export type IColumns = {\n  /**\n   * @description 保持原始内容，不需要处理，不要翻译\n   * @type {string}\n   */\n  title: string;\n  /**\n   * @description 翻译成英文，驼峰格式\n   * @type {string}\n   */\n  dataIndex: string;\n  /**\n   * @description 翻译成英文，驼峰格式\n   * @type {string}\n   */\n  key: string;\n  slot: boolean;\n}[];\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Table 表格/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/blocks/现有模块中添加 antdv Table 表格/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/blocks/现有模块中添加 antdv Table 表格/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: (lowcodeContext) => {},\n  complete: (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    main.handleComplete();\n  },\n  intColumnsFromOcrText: (lowcodeContext) => {\n    let columns = lowcodeContext.params\n      .replace(/\\r\\n/g, '\\n')\n      .replace(/\\r/g, '\\n')\n      .split('\\n');\n    columns = columns.map((s) => ({\n      slot: false,\n      title: s,\n      dataIndex: s,\n      key: s,\n    }));\n    lowcodeContext.outputChannel.appendLine(JSON.stringify(columns));\n    return { ...lowcodeContext.model, columns };\n  },\n  askChatGPT: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    const res = await main.handleAskChatGPT();\n    return res;\n  },\n  intColumnsFromClipboardImage: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    const res = await main.handleIntColumnsFromClipboardImage();\n    return res;\n  },\n  insertPlaceholder: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    main.handleInsertPlaceholder();\n    return context.model;\n  },\n  OCR: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    const res = await main.handleOCR();\n    return res;\n  },\n};\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Table 表格/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { ViewCallContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: ViewCallContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Table 表格/script/src/main.ts",
    "content": "import * as path from 'path';\nimport * as fs from 'fs-extra';\nimport * as execa from 'execa';\nimport * as ejs from 'ejs';\nimport { window, workspace, Range } from 'vscode';\nimport axios from 'axios';\nimport { generalBasic } from '@share/BaiduOCR/index';\nimport { translate } from '@share/TypeChatSlim/index';\nimport { typescriptToMock } from '@share/utils/json';\nimport { context } from './context';\nimport { IColumns } from '../../config/schema';\n\nexport async function handleOCR() {\n  const { lowcodeContext } = context;\n  if (!lowcodeContext?.clipboardImage) {\n    window.showInformationMessage('剪贴板里没有截图');\n    return {\n      updateModelImmediately: false,\n      onlyUpdateParams: true,\n      params: '',\n      model: lowcodeContext?.model,\n    };\n  }\n  const ocrRes = await generalBasic({ image: lowcodeContext!.clipboardImage! });\n  return {\n    updateModelImmediately: false,\n    onlyUpdateParams: true,\n    params: ocrRes.words_result.map((s) => s.words).join('\\r\\n'),\n    model: lowcodeContext?.model,\n  };\n}\n\nexport async function handleAskChatGPT() {\n  const { lowcodeContext } = context;\n  const schema = fs.readFileSync(\n    path.join(lowcodeContext!.materialPath, 'config/schema.ts'),\n    'utf8',\n  );\n  const typeName = 'IColumns';\n  const res = await translate<IColumns>({\n    schema,\n    typeName,\n    request: JSON.stringify(\n      (lowcodeContext!.model as { columns: IColumns }).columns,\n    ),\n    completePrompt:\n      `你是一个根据以下 TypeScript 类型定义将用户请求转换为 \"${typeName}\" 类型的 JSON 对象的服务，并且按照字段的注释进行处理:\\n` +\n      `\\`\\`\\`\\n${schema}\\`\\`\\`\\n` +\n      `以下是用户请求:\\n` +\n      `\"\"\"\\n${JSON.stringify(\n        (lowcodeContext!.model as { columns: IColumns }).columns,\n      )}\\n\"\"\"\\n` +\n      `The following is the user request translated into a JSON object with 2 spaces of indentation and no properties with the value undefined:\\n`,\n    createChatCompletion: lowcodeContext!.createChatCompletion,\n    showWebview: true,\n    extendValidate: (jsonObject) => ({ success: true, data: jsonObject }),\n  });\n  lowcodeContext!.outputChannel.appendLine(JSON.stringify(res, null, 2));\n  if (res.success) {\n    return { ...lowcodeContext!.model, columns: res.data };\n  }\n  return lowcodeContext!.model;\n}\n\nexport async function handleIntColumnsFromClipboardImage() {\n  const { lowcodeContext } = context;\n  if (!lowcodeContext?.clipboardImage) {\n    window.showInformationMessage('剪贴板里获取不到图片');\n    return lowcodeContext?.model;\n  }\n  const ocrRes = await generalBasic({ image: lowcodeContext!.clipboardImage! });\n  const columns = ocrRes.words_result.map((s) => ({\n    slot: false,\n    title: s.words,\n    dataIndex: s.words,\n    key: s.words,\n  }));\n  const schema = fs.readFileSync(\n    path.join(lowcodeContext!.materialPath, 'config/schema.ts'),\n    'utf8',\n  );\n  const typeName = 'IColumns';\n  const res = await translate<IColumns>({\n    schema,\n    typeName,\n    request: JSON.stringify(columns),\n    completePrompt:\n      `你是一个根据以下 TypeScript 类型定义将用户请求转换为 \"${typeName}\" 类型的 JSON 对象的服务，并且按照字段的注释进行处理:\\n` +\n      `\\`\\`\\`\\n${schema}\\`\\`\\`\\n` +\n      `以下是用户请求:\\n` +\n      `\"\"\"\\n${JSON.stringify(columns)}\\n\"\"\"\\n` +\n      `The following is the user request translated into a JSON object with 2 spaces of indentation and no properties with the value undefined:\\n`,\n    createChatCompletion: lowcodeContext!.createChatCompletion,\n    showWebview: true,\n    extendValidate: (jsonObject) => ({ success: true, data: jsonObject }),\n  });\n  lowcodeContext!.outputChannel.appendLine(JSON.stringify(res, null, 2));\n  if (res.success) {\n    return { ...lowcodeContext!.model, columns: res.data };\n  }\n  return lowcodeContext?.model;\n}\n\nexport async function handleInsertPlaceholder() {\n  const { lowcodeContext } = context;\n  if (!lowcodeContext?.activeTextEditor) {\n    window.showInformationMessage('没有激活的文档');\n    return;\n  }\n  lowcodeContext?.activeTextEditor?.edit((editBuilder) => {\n    // editBuilder.replace(activeTextEditor.selection, content);\n    if (lowcodeContext?.activeTextEditor?.selection.isEmpty) {\n      editBuilder.insert(\n        lowcodeContext?.activeTextEditor.selection.start,\n        lowcodeContext!.params,\n      );\n    } else {\n      editBuilder.replace(\n        new Range(\n          lowcodeContext?.activeTextEditor!.selection.start,\n          lowcodeContext?.activeTextEditor!.selection.end,\n        ),\n        lowcodeContext!.params,\n      );\n    }\n  });\n}\nexport async function handleComplete() {\n  const { lowcodeContext } = context;\n  const createBlockPath = context.lowcodeContext?.createBlockPath;\n  if (createBlockPath) {\n    // #region 更新 api.ts 文件\n    const apiFileContent = fs\n      .readFileSync(path.join(createBlockPath, 'temp.api.ts'))\n      .toString();\n\n    let apiFileContentOld = '';\n    try {\n      apiFileContentOld = fs\n        .readFileSync(path.join(createBlockPath, 'api.ts').toString())\n        .toString();\n    } catch {}\n\n    fs.writeFileSync(\n      path.join(createBlockPath, 'api.ts'),\n      apiFileContentOld + apiFileContent,\n    );\n    fs.removeSync(path.join(createBlockPath, 'temp.api.ts'));\n    try {\n      execa.sync('node', [\n        path.join(workspace.rootPath!, '/node_modules/eslint/bin/eslint.js'),\n        path.join(createBlockPath, 'api.ts'),\n        '--resolve-plugins-relative-to',\n        workspace.rootPath!,\n        '--fix',\n      ]);\n    } catch (err) {\n      console.log(err);\n    }\n    // #endregion\n\n    // #region 更新 model.ts 文件\n    const modelFileContent = fs\n      .readFileSync(path.join(createBlockPath, 'temp.model.ts'))\n      .toString();\n    let modelFileContentOld = fs\n      .readFileSync(path.join(createBlockPath, 'model.ts').toString())\n      .toString();\n\n    const keywords = [\n      '// lowcode-model-import-api',\n      '// lowcode-model-type',\n      '// lowcode-model-variable',\n      '// lowcode-model-return-variable',\n    ];\n    const modelSplitArr = modelFileContent.split(\n      new RegExp(keywords.join('|'), 'ig'),\n    );\n    const modelImportApi = modelSplitArr[1].replace(/\\n/g, '');\n    const modelType = modelSplitArr[2];\n    const modelVariable = modelSplitArr[3];\n    const modelReturnVariable = modelSplitArr[4].replace(/\\n/g, '');\n\n    if (!modelFileContentOld.includes('// lowcode-model-import-api')) {\n      modelFileContentOld = `// lowcode-model-import-api\\n${modelFileContentOld}`;\n    }\n    modelFileContentOld = modelFileContentOld.replace(\n      '// lowcode-model-import-api',\n      modelImportApi,\n    );\n\n    if (!modelFileContentOld.includes('// lowcode-model-type')) {\n      modelFileContentOld = modelFileContentOld.replace(\n        'export const useModel',\n        '// lowcode-model-type\\nexport const useModel',\n      );\n    }\n    modelFileContentOld = modelFileContentOld.replace(\n      '// lowcode-model-type',\n      modelType,\n    );\n\n    if (!modelFileContentOld.includes('// lowcode-model-variable')) {\n      modelFileContentOld = modelFileContentOld.replace(\n        'return {',\n        '// lowcode-model-variable\\nreturn {',\n      );\n    }\n    modelFileContentOld = modelFileContentOld.replace(\n      '// lowcode-model-variable',\n      modelVariable,\n    );\n\n    if (!modelFileContentOld.includes('// lowcode-model-return-variable')) {\n      modelFileContentOld = modelFileContentOld.replace(\n        'return {',\n        'return {\\n// lowcode-model-return-variable',\n      );\n    }\n    modelFileContentOld = modelFileContentOld.replace(\n      '// lowcode-model-return-variable',\n      modelReturnVariable,\n    );\n\n    fs.writeFileSync(\n      path.join(createBlockPath, 'model.ts'),\n      modelFileContentOld,\n    );\n    fs.removeSync(path.join(createBlockPath, 'temp.model.ts'));\n    try {\n      execa.sync('node', [\n        path.join(workspace.rootPath!, '/node_modules/eslint/bin/eslint.js'),\n        path.join(createBlockPath, 'model.ts'),\n        '--resolve-plugins-relative-to',\n        workspace.rootPath!,\n        '--fix',\n      ]);\n    } catch (err) {\n      console.log(err);\n    }\n    // #endregion\n\n    // #region 更新 service.ts 文件\n    const serviceFileContent = fs\n      .readFileSync(path.join(createBlockPath, 'temp.service.ts').toString())\n      .toString();\n    let serviceFileContentOld = fs\n      .readFileSync(path.join(createBlockPath, 'service.ts').toString())\n      .toString()\n      .trim();\n\n    const serviceSplitArr = serviceFileContent.split(\n      new RegExp(\n        ['// lowcode-service-import-api', '// lowcode-service-method'].join(\n          '|',\n        ),\n        'ig',\n      ),\n    );\n    const serviceImportApi = serviceSplitArr[1].replace(/\\n/g, '');\n    const serviceMethod = serviceSplitArr[2];\n    if (!serviceFileContentOld.includes('// lowcode-service-import-api')) {\n      serviceFileContentOld = `// lowcode-service-import-api\\n${serviceFileContentOld}`;\n    }\n    serviceFileContentOld = serviceFileContentOld.replace(\n      '// lowcode-service-import-api',\n      serviceImportApi,\n    );\n\n    if (!serviceFileContentOld.includes('// lowcode-service-method')) {\n      serviceFileContentOld = `${serviceFileContentOld.slice(\n        0,\n        serviceFileContentOld.length - 1,\n      )}// lowcode-service-method\\n}`;\n    }\n    serviceFileContentOld = serviceFileContentOld.replace(\n      '// lowcode-service-method',\n      serviceMethod,\n    );\n    fs.writeFileSync(\n      path.join(createBlockPath, 'service.ts'),\n      serviceFileContentOld,\n    );\n    fs.removeSync(path.join(createBlockPath, 'temp.service.ts'));\n    try {\n      execa.sync('node', [\n        path.join(workspace.rootPath!, '/node_modules/eslint/bin/eslint.js'),\n        path.join(createBlockPath, 'service.ts'),\n        '--resolve-plugins-relative-to',\n        workspace.rootPath!,\n        '--fix',\n      ]);\n    } catch (err) {\n      console.log(err);\n    }\n    // #endregion\n\n    // #region 更新 presenter 文件\n    const presenterFileContent = fs\n      .readFileSync(path.join(createBlockPath, 'temp.presenter.ts'))\n      .toString();\n\n    let presenterFile = path.join(createBlockPath, 'presenter.ts');\n    if (!fs.existsSync(presenterFile)) {\n      presenterFile = path.join(createBlockPath, 'presenter.tsx');\n    }\n    let presenterFileContentOld = fs.readFileSync(presenterFile).toString();\n\n    const presenterSplitArr = presenterFileContent.split(\n      new RegExp(\n        [\n          '// lowcode-presenter-handlePageChange',\n          '// lowcode-presenter-return-handlePageChange',\n        ].join('|'),\n        'ig',\n      ),\n    );\n    const presenterMethod = presenterSplitArr[1];\n    const presenterReturnMethod = presenterSplitArr[2];\n\n    if (\n      !presenterFileContentOld.includes('// lowcode-presenter-handlePageChange')\n    ) {\n      presenterFileContentOld = presenterFileContentOld.replace(\n        'return {',\n        `// lowcode-presenter-handlePageChange\\nreturn {`,\n      );\n    }\n    presenterFileContentOld = presenterFileContentOld.replace(\n      '// lowcode-presenter-handlePageChange',\n      presenterMethod,\n    );\n\n    if (\n      !presenterFileContentOld.includes(\n        '// lowcode-presenter-return-handlePageChange',\n      )\n    ) {\n      presenterFileContentOld = presenterFileContentOld.replace(\n        'return {',\n        'return {\\n// lowcode-presenter-return-handlePageChange',\n      );\n    }\n    presenterFileContentOld = presenterFileContentOld.replace(\n      '// lowcode-presenter-return-handlePageChange',\n      presenterReturnMethod,\n    );\n    fs.writeFileSync(presenterFile, presenterFileContentOld);\n    fs.removeSync(path.join(createBlockPath, 'temp.presenter.ts'));\n    try {\n      execa.sync('node', [\n        path.join(workspace.rootPath!, '/node_modules/eslint/bin/eslint.js'),\n        presenterFile,\n        '--resolve-plugins-relative-to',\n        workspace.rootPath!,\n        '--fix',\n      ]);\n    } catch (err) {\n      console.log(err);\n    }\n    // #endregion\n\n    // #region 更新 index.vue 文件\n    const vueFileContent = fs\n      .readFileSync(path.join(createBlockPath, 'temp.index.vue').toString())\n      .toString();\n\n    let vueFileContentOld = fs\n      .readFileSync(path.join(createBlockPath, 'index.vue').toString())\n      .toString();\n\n    const vueSplitArr = vueFileContent.split(\n      new RegExp(\n        ['<!-- lowcode-vue-template -->', '// lowcode-vue-columns'].join('|'),\n        'ig',\n      ),\n    );\n    const vueTemplate = vueSplitArr[1];\n    const vueColumns = vueSplitArr[2];\n\n    if (!vueFileContentOld.includes('<!-- lowcode-vue-template -->')) {\n      const index = vueFileContentOld.lastIndexOf('</template>');\n      vueFileContentOld = `${vueFileContentOld.substring(\n        0,\n        index,\n      )}<!-- lowcode-vue-template -->${vueFileContentOld.substring(index)}`;\n    }\n    vueFileContentOld = vueFileContentOld.replace(\n      '<!-- lowcode-vue-template -->',\n      vueTemplate,\n    );\n\n    if (!vueFileContentOld.includes('// lowcode-vue-columns')) {\n      vueFileContentOld = vueFileContentOld.replace(\n        '</script>',\n        `// lowcode-vue-columns\\n</script>`,\n      );\n    }\n    vueFileContentOld = vueFileContentOld.replace(\n      '// lowcode-vue-columns',\n      vueColumns,\n    );\n\n    fs.writeFileSync(\n      path.join(createBlockPath, 'index.vue'),\n      vueFileContentOld,\n    );\n    fs.removeSync(path.join(createBlockPath, 'temp.index.vue'));\n    try {\n      execa.sync('node', [\n        path.join(workspace.rootPath!, '/node_modules/eslint/bin/eslint.js'),\n        path.join(createBlockPath, 'index.vue'),\n        '--resolve-plugins-relative-to',\n        workspace.rootPath!,\n        '--fix',\n      ]);\n    } catch (err) {\n      console.log(err);\n    }\n    // #endregion\n\n    // #region 更新 mock 服务\n    const mockType = fs\n      .readFileSync(path.join(createBlockPath, 'temp.mock.type').toString())\n      .toString();\n    fs.removeSync(path.join(createBlockPath, 'temp.mock.type'));\n    const { mockCode, mockData } = typescriptToMock(mockType);\n    const mockTemplate = fs\n      .readFileSync(\n        path.join(createBlockPath, 'temp.mock.script.ejs').toString(),\n      )\n      .toString();\n    fs.removeSync(path.join(createBlockPath, 'temp.mock.script.ejs'));\n    const mockScript = ejs.render(mockTemplate, {\n      ...lowcodeContext!.model,\n      mockCode,\n      mockData,\n      createBlockPath: createBlockPath.replace(':', ''),\n    });\n    const mockProjectPathRes = await axios\n      .get('http://localhost:3000/mockProjectPath', { timeout: 1000 })\n      .catch(() => {\n        // window.showErrorMessage('获取 mock 项目路径失败');\n      });\n    if (mockProjectPathRes?.data.result) {\n      const projectName = workspace.rootPath\n        ?.replace(/\\\\/g, '/')\n        .split('/')\n        .pop();\n      const mockRouteFile = path.join(\n        mockProjectPathRes.data.result,\n        `${projectName}.js`,\n      );\n      let mockFileContent = `\n\t\t\timport KoaRouter from 'koa-router';\n\t\t\timport proxy from '../middleware/Proxy';\n\t\t\timport { delay } from '../lib/util';\n\n\t\t\tconst Mock = require('mockjs');\n\n\t\t\tconst { Random } = Mock;\n\n\t\t\tconst router = new KoaRouter();\n\t\t\trouter{{mockScript}}\n\t\t\tmodule.exports = router;\n\t\t\t`;\n\n      if (fs.existsSync(mockRouteFile)) {\n        mockFileContent = fs.readFileSync(mockRouteFile).toString().toString();\n        const index = mockFileContent.lastIndexOf(')') + 1;\n        mockFileContent = `${mockFileContent.substring(\n          0,\n          index,\n        )}{{mockScript}}\\n${mockFileContent.substring(index)}`;\n      }\n      mockFileContent = mockFileContent.replace(/{{mockScript}}/g, mockScript);\n      fs.writeFileSync(mockRouteFile, mockFileContent);\n      try {\n        execa.sync('node', [\n          path.join(\n            mockProjectPathRes.data.result\n              .replace(/\\\\/g, '/')\n              .replace('/src/routes', ''),\n            '/node_modules/eslint/bin/eslint.js',\n          ),\n          mockRouteFile,\n          '--resolve-plugins-relative-to',\n          mockProjectPathRes.data.result\n            .replace(/\\\\/g, '/')\n            .replace('/src/routes', ''),\n          '--fix',\n        ]);\n      } catch (err) {\n        console.log(err);\n      }\n      // #endregion\n    }\n  }\n}\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Table 表格/src/temp.api.ts.ejs",
    "content": "// #region\nexport interface IFetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Result {\n  code: number;\n\tmsg: string;\n\t<% if (!pagination.show) { _%>\n\tresult: {\n\t\t<% columns.map((item, index) => { _%>\n\t\t\t<%= item.key || `column${index+1}` %>: string;\n\t\t<% }) _%>\n\t}[];\n\t<% } else { _%>\n\t\tresult: {\n\t\t\trecords: {\n\t\t\t\t<% columns.map((item, index) => { _%>\n\t\t\t\t\t<%= item.key || `column${index+1}` %>: string;\n\t\t\t\t<% }) _%>\n\t\t\t}[];\n\t\t\ttotal: number;\n\t\t}\n\t<% } _%>\n}\n\nexport interface IFetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Params {\n\t<% if (pagination.show) { _%>\n\t\t<%= pagination.page %>: number;\n\t\t<%= pagination.size %>: number;\n\t<% } _%>\n\tid?: number;\n}\n\nexport function fetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>(\n\tparams: IFetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Params\n) {\n\treturn request<IFetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Result>({\n\t\turl: `http://127.0.0.1:3000<%= createBlockPath.replace(':', '') %>/fetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>`, \n\t\tmethod: 'GET',\n\t\tparams,\n\t});\n}\n// #endregion"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Table 表格/src/temp.index.vue.ejs",
    "content": "<!-- lowcode-vue-template -->\n<a-table\n\t:columns=\"<%= variableName %>TableColumns\"\n\t:data-source=\"model.<%= variableName %>.value\"\n\t:pagination=\"false\"\n>\n\t<template #bodyCell=\"{ column, record }\">\n\t\t<% columns.filter(item => item.slot).map((item, index) => { _%>\n\t\t\t<template v-if=\"column.key === '<%= item.key %>'\">\n\t\t\t\t{{ record.<%= item.key %> }}\n\t\t\t</template>\n\t\t<% }) _%>\n\t\t<template v-if=\"column.key === 'operation'\">\n\t\t\t<a-space :size=\"0\">\n\t\t\t\t<a-button\n\t\t\t\t\ttype=\"link\"\n\t\t\t\t\tsize=\"small\"\n\t\t\t\t>\n\t\t\t\t\t编辑\n\t\t\t\t</a-button>\n\t\t\t</a-space>\n\t\t</template>\n\t</template>\n</a-table>\n<% if(pagination.show) { _%>\n<a-pagination\n\tstyle=\"margin-top: 10px\"\n\t@change=\"presenter.handle<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>PageChange\"\n\t@showSizeChange=\"presenter.handle<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>PageChange\"\n\tv-model:current=\"model.<%= variableName %>Pagination.page\"\n\t:total=\"model.<%= variableName %>Pagination.total\"\n\tshow-size-changer\n\tshow-quick-jumper\n\t:show-total=\"(total:number) => `共搜索到 ${total} 条数据`\"\n></a-pagination>\n<% } _%> \n// lowcode-vue-columns\n\nconst <%= variableName %>TableColumns = [\n\t<% columns.map((item, index) => { _%>\n\t\t{\n\t\t\ttitle: \"<%= item.title || `column${index+1}` %>\",\n\t\t\tdataIndex: \"<%= item.dataIndex || `column${index+1}` %>\",\n\t\t\tkey: \"<%= item.key || `column${index+1}` %>\",\n\t\t\t<% if(item.width) {%>width: \"<%= item.width %>\",<% } _%>\n\t\t},\n\t<% }) _%>\n\t{\n\t\ttitle: \"操作\",\n\t\tkey: \"operation\",\n\t\twidth: 100\n\t}\n];\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Table 表格/src/temp.mock.script.ejs",
    "content": ".get(`<%= createBlockPath %>/fetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>`, async (ctx, next) => { <%- mockCode %> ctx.body = <%- mockData %>\n})\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Table 表格/src/temp.mock.type.ejs",
    "content": "{\n  code: number;\n\tmsg: string;\n\t<% if (!pagination.show) { _%>\n\tresult: {\n\t\t<% columns.map((item, index) => { _%>\n\t\t\t<%= item.key || `column${index+1}` %>: string;\n\t\t<% }) _%>\n\t}[];\n\t<% } else { _%>\n\t\tresult: {\n\t\t\trecords: {\n\t\t\t\t<% columns.map((item, index) => { _%>\n\t\t\t\t\t<%= item.key || `column${index+1}` %>: string;\n\t\t\t\t<% }) _%>\n\t\t\t}[];\n\t\t\ttotal: number;\n\t\t}\n\t<% } _%>\n}"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Table 表格/src/temp.model.ts.ejs",
    "content": "// lowcode-model-import-api\nimport { IFetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Result } from \"./api\";\n// lowcode-model-type\ninterface I<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Item {\n\t<% columns.map((item, index) => { _%>\n\t\t/** <%= item.title %> */\n\t\t<%= item.key || `column${index+1}` %>: string;\n\t<% }) _%>\n\t/**\n   * 接口返回的数据，新增字段不需要改 I<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Item 直接从这里取\n   */\n\tapiResult: IFetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Result<%- result %>[0]\n}\n// lowcode-model-variable\nconst <%= variableName %> = ref<I<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>Item[]>(\n\t\t\t[],\n\t\t);\n<% if(pagination.show) { %>\n\tconst <%= variableName %>Pagination = reactive<{\n\t\tpage: number;\n\t\tpageSize: number;\n\t\ttotal: number;\n\t}>({\n\t\tpage: 1,\n\t\tpageSize: 10,\n\t\ttotal: 0,\n\t});\n<% } %>\n// lowcode-model-return-variable\n<%= variableName %>,\n<% if(pagination.show) { _%>\n\t<%= variableName %>Pagination,\n<% } _%>\n"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Table 表格/src/temp.presenter.ts.ejs",
    "content": "  // lowcode-presenter-handlePageChange\n\t<% if(pagination.show) { _%>\n  const handle<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>PageChange = (page: number, pageSize: number) => {\n    if (pageSize !== model.<%= variableName %>Pagination.pageSize) {\n      model.<%= variableName %>Pagination.pageSize = pageSize;\n      model.<%= variableName %>Pagination.page = 1;\n    } else {\n      model.<%= variableName %>Pagination.page = page;\n    }\n    service.get<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>();\n  };\n  <% } _%>\n\t// lowcode-presenter-return-handlePageChange\n\t<% if(pagination.show) { _%>\n\thandle<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>PageChange,\n  <% } _%>\n\t"
  },
  {
    "path": "materials/blocks/现有模块中添加 antdv Table 表格/src/temp.service.ts.ejs",
    "content": "// lowcode-service-import-api\nimport {fetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>} from './api';\n// lowcode-service-method\nasync get<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>() {\n\tconst res = await fetch<%= variableName.slice(0, 1).toUpperCase() + variableName.slice(1) %>({})\n\tthis.model.<%= variableName %>.value = res<%- result %>.map((s) => {\n\t\treturn {\n\t...s,\n\t<% columns.map((item, index) => { _%>\n\t\t<%= item.key || `column${index+1}` %>: s.<%= item.key || `column${index+1}` %>,\n\t<% }) _%>\n\tapiResult: s\n\t\t};\n\t});\n\t<% if(pagination.show) { _%>\n\tthis.model.<%= variableName %>Pagination.total = res.<%- pagination.total %>;\n\t<% } _%>\n}\n"
  },
  {
    "path": "materials/blocks/通过 ast 给 antdv Descriptions 描述列表添加字段/config/model.json",
    "content": "{\n  \"name\": \"lowcode\"\n}"
  },
  {
    "path": "materials/blocks/通过 ast 给 antdv Descriptions 描述列表添加字段/config/preview.json",
    "content": "{\n\t\"title\": \"通过 ast 给 antdv Descriptions 描述列表添加字段\",\n\t\"description\": \"现有模块必须是遵循整洁架构的目录结构,否则无法使用\",\n\t\"img\": [\n\t\t\"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n\t],\n\t\"category\": [],\n\t\"schema\": \"amis\",\n\t\"scripts\": [\n\t\t{\n\t\t\t\"method\": \"test\",\n\t\t\t\"remark\": \"测试一下\"\n\t\t}\n\t]\n}"
  },
  {
    "path": "materials/blocks/通过 ast 给 antdv Descriptions 描述列表添加字段/config/schema.json",
    "content": "{\n  \"formSchema\": {\n    \"schema\": {\n      \"type\": \"page\",\n      \"body\": [\n        {\n          \"type\": \"form\",\n          \"title\": \"\",\n          \"body\": [\n            {\n              \"type\": \"input-text\",\n              \"name\": \"name\",\n              \"label\": \"测试表单\",\n              \"id\": \"u:4886baa626cf\",\n              \"value\": \"\"\n            }\n          ],\n          \"id\": \"u:67967afb0e69\",\n          \"submitText\": \"\"\n        }\n      ],\n      \"id\": \"u:d87dbf6bf8df\",\n      \"asideResizor\": false,\n      \"style\": {\n        \"boxShadow\": \" 0px 0px 0px 0px transparent\"\n      },\n      \"pullRefresh\": {\n        \"disabled\": true\n      },\n      \"regions\": [\n        \"body\"\n      ]\n    },\n    \"conditionFiles\": {\n      \"name\": {\n        \"value\": \"123\",\n        \"exclude\": [\n          \"当表单name的值为123,删除这个数组里的文件.ejs\"\n        ]\n      }\n    },\n    \"excludeCompile\": [\n      \"不需要编译的文件,不会被删除.ejs\"\n    ]\n  }\n}"
  },
  {
    "path": "materials/blocks/通过 ast 给 antdv Descriptions 描述列表添加字段/config/viewPrompt.ejs",
    "content": "<%- model %> \r\n将这段 json 中，中文 key 翻译为英文，使用驼峰语法，\r\n返回翻译后的markdown语法的代码块"
  },
  {
    "path": "materials/blocks/通过 ast 给 antdv Descriptions 描述列表添加字段/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/blocks/通过 ast 给 antdv Descriptions 描述列表添加字段/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/blocks/通过 ast 给 antdv Descriptions 描述列表添加字段/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (context) => {\n    const compileHandler =\n      new main.CompileHandlerb9e78736b4ba410186eabffd9a749388(context);\n    compileHandler.log('compile start');\n  },\n  afterCompile: (context) => {\n    const compileHandler =\n      new main.CompileHandlerb9e78736b4ba410186eabffd9a749388(context);\n    compileHandler.log('compile end');\n  },\n  complete: (context) => {\n    const compileHandler =\n      new main.CompileHandlerb9e78736b4ba410186eabffd9a749388(context);\n    compileHandler.updateModel();\n    compileHandler.log('compile complete');\n  },\n  intFromOcrText: (context) => {\n    const viewCallHandler =\n      new main.ViewCallHandlerb9e78736b4ba410186eabffd9a749388(context);\n    viewCallHandler.log('call method intFromOcrText');\n    viewCallHandler.showInformationMessage('lowcode');\n    return viewCallHandler.intFromOcrText();\n  },\n  test: (context) => ({ ...context.model, name: '测试一下' }),\n};\n"
  },
  {
    "path": "materials/blocks/通过 ast 给 antdv Descriptions 描述列表添加字段/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { CompileContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/blocks/通过 ast 给 antdv Descriptions 描述列表添加字段/script/src/main.ts",
    "content": "import path from 'path';\nimport * as typescriptParse from 'recast/parsers/typescript';\nimport * as recast from 'recast';\nimport fs from 'fs-extra';\nimport { visit, builders } from 'ast-types';\nimport { IdentifierKind } from 'ast-types/gen/kinds';\nimport { CompileContext, ViewCallContext } from 'lowcode-context';\n\nexport class CompileHandlerb9e78736b4ba410186eabffd9a749388 {\n  private context!: CompileContext;\n\n  constructor(context: CompileContext) {\n    this.context = context;\n  }\n\n  log(value: string) {\n    this.context.outputChannel.appendLine(value);\n  }\n\n  updateModel() {\n    const code = fs.readFileSync(\n      path.join(this.context.createBlockPath!, 'model.ts'),\n      'utf-8',\n    );\n\n    const ast = recast.parse(code, { parser: typescriptParse });\n    const fieldName = 'name';\n    const fieldType = 'string';\n\n    visit(ast, {\n      visitTSInterfaceDeclaration: (nodePath) => {\n        const members = nodePath.node.body.body;\n        if ((nodePath.node.id as IdentifierKind).name === 'IDetailInfo') {\n          members.push(\n            builders.tsPropertySignature(\n              builders.identifier(fieldName),\n              builders.tsTypeAnnotation(builders.tsStringKeyword()),\n            ),\n          );\n        }\n        return false;\n      },\n    });\n\n    visit(ast, {\n      visitVariableDeclaration(nodePath) {\n        const declaration = nodePath.node.declarations[0];\n        if (\n          // @ts-ignore\n          declaration.id.name === 'defaultFormData' &&\n          // @ts-ignore\n          declaration.init.type === 'ObjectExpression'\n        ) {\n          // @ts-ignore\n          declaration.init.properties.push(\n            builders.objectProperty(\n              builders.identifier(fieldName),\n              builders.stringLiteral(''),\n            ),\n          );\n        }\n        return false;\n      },\n    });\n\n    const newCode = recast.print(ast).code;\n    fs.writeFileSync(\n      path.join(this.context.createBlockPath!, 'model.ts'),\n      newCode,\n    );\n  }\n}\n\nexport class ViewCallHandlerb9e78736b4ba410186eabffd9a749388 {\n  private context!: ViewCallContext;\n\n  constructor(context: ViewCallContext) {\n    this.context = context;\n  }\n\n  log(value: string) {\n    this.context.outputChannel.appendLine(value);\n  }\n\n  intFromOcrText() {\n    return Promise.resolve({ ...this.context.model, name: '测试一下' });\n  }\n}\n"
  },
  {
    "path": "materials/blocks/通过 ast 给 antdv Descriptions 描述列表添加字段/src/README.md",
    "content": "在当前文件夹下放区块模板，并将此文件删除"
  },
  {
    "path": "materials/blocks/通过脚本启动一个 nest api 服务/config/model.json",
    "content": "{\n  \"name\": \"通过脚本启动一个 nest api 服务\"\n}"
  },
  {
    "path": "materials/blocks/通过脚本启动一个 nest api 服务/config/preview.json",
    "content": "{\n  \"title\": \"通过脚本启动一个 nest api 服务\",\n  \"description\": \"通过脚本启动一个 nest api 服务\",\n  \"img\": [\n    \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n  ],\n  \"category\": [],\n  \"schema\": \"amis\",\n  \"scripts\": [\n    {\n      \"method\": \"startNestApiServer\",\n      \"remark\": \"启动 nest api 服务\"\n    }\n  ]\n}"
  },
  {
    "path": "materials/blocks/通过脚本启动一个 nest api 服务/config/schema.json",
    "content": "{\n  \"formSchema\": {\n    \"schema\": {\n      \"type\": \"page\",\n      \"body\": [\n        {\n          \"type\": \"form\",\n          \"title\": \"\",\n          \"body\": [\n            {\n              \"type\": \"input-text\",\n              \"name\": \"name\",\n              \"label\": \"测试表单\",\n              \"id\": \"u:4886baa626cf\",\n              \"value\": \"\"\n            }\n          ],\n          \"id\": \"u:67967afb0e69\",\n          \"submitText\": \"\"\n        }\n      ],\n      \"id\": \"u:d87dbf6bf8df\",\n      \"asideResizor\": false,\n      \"style\": {\n        \"boxShadow\": \" 0px 0px 0px 0px transparent\"\n      },\n      \"pullRefresh\": {\n        \"disabled\": true\n      },\n      \"regions\": [\n        \"body\"\n      ]\n    },\n    \"conditionFiles\": {\n      \"name\": {\n        \"value\": \"123\",\n        \"exclude\": [\n          \"当表单name的值为123,删除这个数组里的文件.ejs\"\n        ]\n      }\n    },\n    \"excludeCompile\": [\n      \"不需要编译的文件,不会被删除.ejs\"\n    ]\n  }\n}"
  },
  {
    "path": "materials/blocks/通过脚本启动一个 nest api 服务/config/viewPrompt.ejs",
    "content": "<%- model %> \r\n将这段 json 中，中文 key 翻译为英文，使用驼峰语法，\r\n返回翻译后的markdown语法的代码块"
  },
  {
    "path": "materials/blocks/通过脚本启动一个 nest api 服务/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/blocks/通过脚本启动一个 nest api 服务/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/blocks/通过脚本启动一个 nest api 服务/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: (lowcodeContext) => {},\n  startNestApiServer: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    await main.bootstrap();\n    return { ...lowcodeContext.model };\n  },\n};\n"
  },
  {
    "path": "materials/blocks/通过脚本启动一个 nest api 服务/script/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "materials/blocks/通过脚本启动一个 nest api 服务/script/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { ConfigModule } from '@nestjs/config';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\n\n@Module({\n  imports: [\n    ConfigModule.forRoot({\n      envFilePath: `.env.${process.env.NODE_ENV}`,\n      isGlobal: true,\n    }),\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "materials/blocks/通过脚本启动一个 nest api 服务/script/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { context } from './context';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return context.lowcodeContext?.env.rootPath || 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "materials/blocks/通过脚本启动一个 nest api 服务/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { ViewCallContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: ViewCallContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/blocks/通过脚本启动一个 nest api 服务/script/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { context } from './context';\n\nexport async function bootstrap() {\n  const lowcodeContext = context.lowcodeContext!;\n  if (!context.statusBarItem) {\n    const statusBarItem = lowcodeContext.vscode.window.createStatusBarItem(\n      lowcodeContext.vscode.StatusBarAlignment.Left,\n    );\n    context.statusBarItem = statusBarItem;\n  }\n  if (!context.nestApp) {\n    context.statusBarItem.text = '$(loading~spin) Start nest api server...';\n    context.statusBarItem.show();\n    const app = await NestFactory.create(AppModule);\n    await app\n      .listen(3000)\n      .then(() => {\n        context.nestApp = app;\n        if (context.statusBarItem) {\n          context.statusBarItem.text =\n            '$(circle-slash) Low Code Server Port : 3000';\n          context.statusBarItem.tooltip = 'Click to close nest api server';\n          // vscode 限制命令唯一，但是唯一的话命令回调里的 context 永远是同一个\n          const command = `lowcode.StopNestApiServer${new Date().getTime()}`;\n          try {\n            const dsisposable = lowcodeContext.vscode.commands.registerCommand(\n              command,\n              () => {\n                context.statusBarItem!.text = '$(loading~spin) close...';\n                context.statusBarItem!.command = undefined;\n                context.nestApp?.close().then(() => {\n                  context.nestApp = undefined;\n                  context.statusBarItem?.hide();\n                  context.statusBarItem?.dispose();\n                  context.statusBarItem = undefined;\n                  dsisposable.dispose();\n                });\n              },\n            );\n          } catch (ex) {\n            /* empty */\n          }\n          context.statusBarItem.command = command;\n        }\n      })\n      .catch((ex) => {\n        context.statusBarItem?.hide();\n        context.statusBarItem?.dispose();\n        context.statusBarItem = undefined;\n        throw ex;\n      });\n  }\n}\n"
  },
  {
    "path": "materials/blocks/通过脚本启动一个 nest api 服务/src/README.md",
    "content": "在当前文件夹下放区块模板，并将此文件删除"
  },
  {
    "path": "materials/snippets/OCR/config/commandPrompt.ejs",
    "content": "\n"
  },
  {
    "path": "materials/snippets/OCR/config/model.json",
    "content": "{\n  \"name\": \"lowcode\"\n}"
  },
  {
    "path": "materials/snippets/OCR/config/preview.json",
    "content": "{\n\t\"title\": \"\",\n\t\"description\": \"\",\n\t\"img\": [\n\t\t\"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n\t],\n\t\"category\": [],\n\t\"notShowInCommand\": true,\n\t\"notShowInSnippetsList\": true,\n\t\"notShowInintellisense\": true,\n\t\"showInRunSnippetScript\": true,\n\t\"schema\": \"amis\",\n\t\"scripts\": []\n}"
  },
  {
    "path": "materials/snippets/OCR/config/schema.json",
    "content": "{\n  \"formSchema\": {\n    \"schema\": {\n      \"type\": \"page\",\n      \"body\": [\n        {\n          \"type\": \"form\",\n          \"title\": \"\",\n          \"body\": [\n            {\n              \"type\": \"input-text\",\n              \"name\": \"name\",\n              \"label\": \"测试表单\",\n              \"id\": \"u:4886baa626cf\",\n              \"value\": \"\"\n            }\n          ],\n          \"id\": \"u:67967afb0e69\",\n          \"submitText\": \"\"\n        }\n      ],\n      \"id\": \"u:d87dbf6bf8df\",\n      \"asideResizor\": false,\n      \"style\": {\n        \"boxShadow\": \" 0px 0px 0px 0px transparent\"\n      },\n      \"pullRefresh\": {\n        \"disabled\": true\n      },\n      \"regions\": [\n        \"body\"\n      ]\n    }\n  }\n}"
  },
  {
    "path": "materials/snippets/OCR/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/OCR/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/OCR/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: (lowcodeContext) => {},\n  onSelect: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    await main.bootstrap();\n  },\n};\n"
  },
  {
    "path": "materials/snippets/OCR/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { ViewCallContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: ViewCallContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/OCR/script/src/main.ts",
    "content": "import { window, Range, env } from 'vscode';\nimport { generalBasic } from '@share/BaiduOCR/index';\nimport { context } from './context';\n\nexport async function bootstrap() {\n  const { lowcodeContext } = context;\n  const clipboardImage = await lowcodeContext?.getClipboardImage();\n  const ocrRes = await generalBasic({ image: clipboardImage! });\n  const words = ocrRes.words_result.map((s) => s.words).join(',');\n  env.clipboard.writeText(words).then(() => {\n    window.showInformationMessage('内容已经复制到剪贴板');\n  });\n  window.activeTextEditor?.edit((editBuilder) => {\n    // editBuilder.replace(activeTextEditor.selection, content);\n    if (window.activeTextEditor?.selection.isEmpty) {\n      editBuilder.insert(window.activeTextEditor.selection.start, words);\n    } else {\n      editBuilder.replace(\n        new Range(\n          window.activeTextEditor!.selection.start,\n          window.activeTextEditor!.selection.end,\n        ),\n        words,\n      );\n    }\n  });\n}\n"
  },
  {
    "path": "materials/snippets/OCR/src/template.ejs",
    "content": ""
  },
  {
    "path": "materials/snippets/OCR + ChatGPT 翻译/config/model.json",
    "content": "{\n  \"name\": \"lowcode\"\n}"
  },
  {
    "path": "materials/snippets/OCR + ChatGPT 翻译/config/preview.json",
    "content": "{\n\t\"title\": \"\",\n\t\"description\": \"\",\n\t\"img\": [\n\t\t\"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n\t],\n\t\"category\": [],\n\t\"notShowInCommand\": true,\n\t\"notShowInSnippetsList\": true,\n\t\"notShowInintellisense\": true,\n\t\"showInRunSnippetScript\": true,\n\t\"schema\": \"amis\",\n\t\"scripts\": []\n}"
  },
  {
    "path": "materials/snippets/OCR + ChatGPT 翻译/config/schema.json",
    "content": "{\n  \"formSchema\": {\n    \"schema\": {\n      \"type\": \"page\",\n      \"body\": [\n        {\n          \"type\": \"form\",\n          \"title\": \"\",\n          \"body\": [\n            {\n              \"type\": \"input-text\",\n              \"name\": \"name\",\n              \"label\": \"测试表单\",\n              \"id\": \"u:4886baa626cf\",\n              \"value\": \"\"\n            }\n          ],\n          \"id\": \"u:67967afb0e69\",\n          \"submitText\": \"\"\n        }\n      ],\n      \"id\": \"u:d87dbf6bf8df\",\n      \"asideResizor\": false,\n      \"style\": {\n        \"boxShadow\": \" 0px 0px 0px 0px transparent\"\n      },\n      \"pullRefresh\": {\n        \"disabled\": true\n      },\n      \"regions\": [\n        \"body\"\n      ]\n    }\n  }\n}"
  },
  {
    "path": "materials/snippets/OCR + ChatGPT 翻译/config/schema.ts",
    "content": "export type IColumns = {\n  /**\n   * @description 保持原始内容，不需要处理，不要翻译\n   * @type {string}\n   */\n  title: string;\n  /**\n   * @description 翻译成英文，驼峰格式\n   * @type {string}\n   */\n  dataIndex: string;\n  /**\n   * @description 翻译成英文，驼峰格式\n   * @type {string}\n   */\n  key: string;\n  slots: {\n    /**\n     * @description 翻译成英文，驼峰格式\n     * @type {string}\n     */\n    customRender: string;\n  };\n}[];\n"
  },
  {
    "path": "materials/snippets/OCR + ChatGPT 翻译/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/OCR + ChatGPT 翻译/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/OCR + ChatGPT 翻译/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: (lowcodeContext) => {},\n  onSelect: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    await main.bootstrap();\n  },\n};\n"
  },
  {
    "path": "materials/snippets/OCR + ChatGPT 翻译/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { CompileContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/OCR + ChatGPT 翻译/script/src/main.ts",
    "content": "import * as path from 'path';\nimport * as fs from 'fs-extra';\nimport { window, Range } from 'vscode';\nimport { generalBasic } from '@share/BaiduOCR/index';\nimport { translate } from '@share/TypeChatSlim/index';\nimport { context } from './context';\nimport { IColumns } from '../../config/schema';\n\nexport async function bootstrap() {\n  const { lowcodeContext } = context;\n  const clipboardImage = await lowcodeContext?.getClipboardImage();\n  const ocrRes = await generalBasic({ image: clipboardImage! });\n  const columns = ocrRes.words_result.map((s) => ({\n    title: s.words,\n    dataIndex: s.words,\n    key: s.words,\n    slots: {\n      customRender: s.words,\n    },\n  }));\n  const schema = fs.readFileSync(\n    path.join(lowcodeContext!.materialPath, 'config/schema.ts'),\n    'utf8',\n  );\n  const typeName = 'IColumns';\n  const res = await translate<IColumns>({\n    schema,\n    typeName,\n    request: JSON.stringify(columns),\n    completePrompt:\n      `你是一个根据以下 TypeScript 类型定义将用户请求转换为 \"${typeName}\" 类型的 JSON 对象的服务，并且按照字段的注释进行处理:\\n` +\n      `\\`\\`\\`\\n${schema}\\`\\`\\`\\n` +\n      `以下是用户请求:\\n` +\n      `\"\"\"\\n${JSON.stringify(columns)}\\n\"\"\"\\n` +\n      `The following is the user request translated into a JSON object with 2 spaces of indentation and no properties with the value undefined:\\n`,\n    createChatCompletion: lowcodeContext!.createChatCompletion,\n    showWebview: true,\n    extendValidate: (jsonObject) => ({ success: true, data: jsonObject }),\n  });\n  let insertText = '';\n  if (res.success) {\n    insertText = JSON.stringify(res.data, null, 2);\n  } else {\n    insertText = JSON.stringify(res, null, 2);\n  }\n  window.activeTextEditor?.edit((editBuilder) => {\n    // editBuilder.replace(activeTextEditor.selection, content);\n    if (lowcodeContext?.activeTextEditor?.selection.isEmpty) {\n      editBuilder.insert(window.activeTextEditor!.selection.start, insertText);\n    } else {\n      editBuilder.replace(\n        new Range(\n          window.activeTextEditor!.selection.start,\n          window.activeTextEditor!.selection.end,\n        ),\n        insertText,\n      );\n    }\n  });\n}\n"
  },
  {
    "path": "materials/snippets/OCR + ChatGPT 翻译/src/template.ejs",
    "content": ""
  },
  {
    "path": "materials/snippets/Pro Chat/config/model.json",
    "content": "{\n  \"name\": \"lowcode\"\n}"
  },
  {
    "path": "materials/snippets/Pro Chat/config/preview.json",
    "content": "{\n\t\"title\": \"\",\n\t\"description\": \"\",\n\t\"img\": [\n\t\t\"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n\t],\n\t\"category\": [],\n\t\"notShowInCommand\": true,\n\t\"notShowInSnippetsList\": true,\n\t\"notShowInintellisense\": true,\n\t\"showInRunSnippetScript\": true,\n\t\"schema\": \"amis\",\n\t\"scripts\": []\n}"
  },
  {
    "path": "materials/snippets/Pro Chat/config/schema.json",
    "content": "{\n  \"formSchema\": {\n    \"schema\": {\n      \"type\": \"page\",\n      \"body\": [\n        {\n          \"type\": \"form\",\n          \"title\": \"\",\n          \"body\": [\n            {\n              \"type\": \"input-text\",\n              \"name\": \"name\",\n              \"label\": \"测试表单\",\n              \"id\": \"u:4886baa626cf\",\n              \"value\": \"\"\n            }\n          ],\n          \"id\": \"u:67967afb0e69\",\n          \"submitText\": \"\"\n        }\n      ],\n      \"id\": \"u:d87dbf6bf8df\",\n      \"asideResizor\": false,\n      \"style\": {\n        \"boxShadow\": \" 0px 0px 0px 0px transparent\"\n      },\n      \"pullRefresh\": {\n        \"disabled\": true\n      },\n      \"regions\": [\n        \"body\"\n      ]\n    }\n  }\n}"
  },
  {
    "path": "materials/snippets/Pro Chat/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/Pro Chat/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/Pro Chat/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: (lowcodeContext) => {},\n  onSelect: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    await main.bootstrap();\n  },\n};\n"
  },
  {
    "path": "materials/snippets/Pro Chat/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { CompileContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/Pro Chat/script/src/controller.ts",
    "content": "import * as vscode from 'vscode';\nimport { CompileContext } from 'lowcode-context';\nimport { createChatCompletion } from '@share/LLM/gemini';\nimport { createChatCompletion as createChatGPTChatCompletion } from '@share/LLM/openai';\nimport { invokeLLMChunkCallback } from '@share/WebView/callback';\nimport { IMessage } from '@share/WebView/type';\n\nconst API_KEY = 'lowcode.GeminiKey';\n\ntype Message = (\n  | {\n      role: 'system';\n      content: string;\n    }\n  | {\n      role: 'user';\n      content:\n        | string\n        | (\n            | {\n                type: 'image_url';\n                image_url: { url: string };\n              }\n            | { type: 'text'; text: string }\n          )[];\n    }\n)[];\n\nexport const askGemini = async (\n  message: IMessage<{\n    messages: Message;\n  }>,\n  lowcodeContext: {\n    webview: vscode.Webview;\n  } & CompileContext,\n) => {\n  const context = lowcodeContext.env.extensionContext;\n  // await context.secrets.delete(API_KEY); // 需要更新 API KEY 的时候打开\n  let apiKey = await context.secrets.get(API_KEY);\n\n  if (!apiKey) {\n    vscode.window.showWarningMessage('Enter your API KEY to save it securely.');\n    apiKey = await setApiKey(context);\n    if (!apiKey) {\n      invokeLLMChunkCallback(lowcodeContext.webview, message.cbid, {\n        content: 'Please enter your api key',\n      });\n      return {\n        content: 'Please enter your api key',\n      };\n    }\n  }\n  const res = await createChatCompletion({\n    model: message.data.messages.some(\n      (s) =>\n        Array.isArray(s.content) &&\n        s.content.some((c) => c.type === 'image_url'),\n    )\n      ? 'gemini-pro-vision'\n      : 'gemini-pro',\n    apiKey,\n    messages: message.data.messages,\n    handleChunk: (data) => {\n      invokeLLMChunkCallback(lowcodeContext.webview, message.cbid, {\n        content: data.text,\n      });\n    },\n    proxyUrl: 'http://127.0.0.1:7890',\n  });\n  return {\n    content: res,\n  };\n};\n\nexport const askChatGPT = async (\n  message: IMessage<{\n    messages: Message;\n  }>,\n  lowcodeContext: {\n    webview: vscode.Webview;\n  } & CompileContext,\n) => {\n  const res = await createChatGPTChatCompletion({\n    model: message.data.messages.some(\n      (s) =>\n        Array.isArray(s.content) &&\n        s.content.some((c) => c.type === 'image_url'),\n    )\n      ? 'gpt-4-vision-preview'\n      : undefined,\n    messages: message.data.messages,\n    handleChunk: (data) => {\n      invokeLLMChunkCallback(lowcodeContext.webview, message.cbid, {\n        content: data.text,\n      });\n    },\n  });\n  return {\n    content: res,\n  };\n};\n\nasync function setApiKey(context) {\n  const apiKey = await vscode.window.showInputBox({\n    title: 'Enter your API KEY',\n    password: true,\n    placeHolder: '**************************************',\n    ignoreFocusOut: true,\n  });\n\n  if (!apiKey) {\n    vscode.window.showWarningMessage('Empty value');\n    return;\n  }\n\n  await context.secrets.store(API_KEY, apiKey);\n  return apiKey;\n}\n"
  },
  {
    "path": "materials/snippets/Pro Chat/script/src/main.ts",
    "content": "import { window } from 'vscode';\nimport { showWebView } from '@share/WebView';\nimport { routes } from './routes';\nimport { context } from './context';\n\nexport async function bootstrap() {\n  const { lowcodeContext } = context;\n  showWebView({\n    key: 'main',\n    title: 'lowcode chat',\n    viewColumn: 3,\n    task: {\n      task: 'route',\n      data: { path: '/chat', materialPath: lowcodeContext?.materialPath },\n    },\n    lowcodeContext: {\n      ...lowcodeContext!,\n    },\n    htmlForWebview: getHtmlForWebview(false),\n    routes,\n  });\n}\n\nconst getHtmlForWebview = (dev = false) => {\n  if (dev) {\n    return `\n\t\t\t\t<!doctype html>\n\t\t\t\t<html lang=\"en\">\n\t\t\t\t\t<head>\n\t\t\t\t\t\t<script type=\"module\">import { injectIntoGlobalHook } from \"http://127.0.0.1:5173/@react-refresh\";\n\t\t\t\t\t\tinjectIntoGlobalHook(window);\n\t\t\t\t\t\twindow.$RefreshReg$ = () => {};\n\t\t\t\t\t\twindow.$RefreshSig$ = () => (type) => type;</script>\n\n\t\t\t\t\t\t<script type=\"module\" src=\"http://127.0.0.1:5173/@vite/client\"></script>\n\t\t\t\t\t\t<script>\n\t\t\t\t\t\t\twindow.vscode = acquireVsCodeApi();\n\t\t\t\t\t\t</script>\n\t\t\t\t\t\t<meta charset=\"UTF-8\" />\n\t\t\t\t\t\t<link rel=\"icon\" type=\"image/svg+xml\" href=\"http://127.0.0.1:5173/vite.svg\" />\n\t\t\t\t\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n\t\t\t\t\t</head>\n\t\t\t\t\t<body>\n\t\t\t\t\t\t<div id=\"root\"></div>\n\t\t\t\t\t\t<script type=\"module\" src=\"http://127.0.0.1:5173/src/main.tsx\"></script>\n\t\t\t\t\t</body>\n\t\t\t\t</html>\n\t\t`;\n  }\n  return `\n\t\t\t<!DOCTYPE html>\n\t\t\t<html>\n\t\t\t<head>\n\t\t\t\t<meta charset=\"utf-8\" />\n\t\t\t\t<meta\n\t\t\t\t\tname=\"viewport\"\n\t\t\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no\"\n\t\t\t\t/>\n\t\t\t\t<script>\n\t\t\t\t   window.vscode = acquireVsCodeApi();\n        </script>\n\t\t\t\t<script type=\"module\" crossorigin src=\"http://lowcode-utools.oss-cn-beijing.aliyuncs.com/vscode.index.js\"></script>\n\t\t\t\t<link rel=\"stylesheet\" crossorigin href=\"http://lowcode-utools.oss-cn-beijing.aliyuncs.com/vscode.index.css\">\n\t\t\t</head>\n\t\t\t<body>\n\t\t\t\t<div id=\"root\"></div>\n\t\t\t</body>\n\t\t</html>\n`;\n};\n"
  },
  {
    "path": "materials/snippets/Pro Chat/script/src/routes.ts",
    "content": "import * as controller from './controller';\n\nexport const routes: Record<string, any> = {\n  askGemini: controller.askGemini,\n  askChatGPT: controller.askChatGPT,\n};\n"
  },
  {
    "path": "materials/snippets/Pro Chat + Tldraw/config/model.json",
    "content": "{\n  \"name\": \"lowcode\"\n}"
  },
  {
    "path": "materials/snippets/Pro Chat + Tldraw/config/preview.json",
    "content": "{\n\t\"title\": \"\",\n\t\"description\": \"\",\n\t\"img\": [\n\t\t\"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n\t],\n\t\"category\": [],\n\t\"notShowInCommand\": true,\n\t\"notShowInSnippetsList\": true,\n\t\"notShowInintellisense\": true,\n\t\"showInRunSnippetScript\": true,\n\t\"schema\": \"amis\",\n\t\"scripts\": []\n}"
  },
  {
    "path": "materials/snippets/Pro Chat + Tldraw/config/schema.json",
    "content": "{\n  \"formSchema\": {\n    \"schema\": {\n      \"type\": \"page\",\n      \"body\": [\n        {\n          \"type\": \"form\",\n          \"title\": \"\",\n          \"body\": [\n            {\n              \"type\": \"input-text\",\n              \"name\": \"name\",\n              \"label\": \"测试表单\",\n              \"id\": \"u:4886baa626cf\",\n              \"value\": \"\"\n            }\n          ],\n          \"id\": \"u:67967afb0e69\",\n          \"submitText\": \"\"\n        }\n      ],\n      \"id\": \"u:d87dbf6bf8df\",\n      \"asideResizor\": false,\n      \"style\": {\n        \"boxShadow\": \" 0px 0px 0px 0px transparent\"\n      },\n      \"pullRefresh\": {\n        \"disabled\": true\n      },\n      \"regions\": [\n        \"body\"\n      ]\n    }\n  }\n}"
  },
  {
    "path": "materials/snippets/Pro Chat + Tldraw/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/Pro Chat + Tldraw/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/Pro Chat + Tldraw/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: (lowcodeContext) => {},\n  onSelect: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    await main.bootstrap();\n  },\n};\n"
  },
  {
    "path": "materials/snippets/Pro Chat + Tldraw/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { CompileContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/Pro Chat + Tldraw/script/src/controller.ts",
    "content": "import * as vscode from 'vscode';\nimport { CompileContext } from 'lowcode-context';\nimport { createChatCompletion } from '@share/LLM/gemini';\nimport { createChatCompletion as createChatGPTChatCompletion } from '@share/LLM/openai';\nimport { invokeLLMChunkCallback } from '@share/WebView/callback';\nimport { IMessage } from '@share/WebView/type';\n\nconst API_KEY = 'lowcode.GeminiKey';\n\nexport const getMaterialPath = async (\n  message: IMessage<{\n    materialPath: string;\n    script: string;\n    params: string;\n  }>,\n  context: {\n    webview: vscode.Webview;\n    task: { task: string; data?: any };\n  } & CompileContext,\n) => context.materialPath;\n\ntype Message = (\n  | {\n      role: 'system';\n      content: string;\n    }\n  | {\n      role: 'user';\n      content:\n        | string\n        | (\n            | {\n                type: 'image_url';\n                image_url: { url: string };\n              }\n            | { type: 'text'; text: string }\n          )[];\n    }\n)[];\nexport const askGemini = async (\n  message: IMessage<{\n    messages: Message;\n  }>,\n  lowcodeContext: {\n    webview: vscode.Webview;\n  } & CompileContext,\n) => {\n  const context = lowcodeContext.env.extensionContext;\n  // await context.secrets.delete(API_KEY); // 需要更新 API KEY 的时候打开\n  let apiKey = await context.secrets.get(API_KEY);\n\n  if (!apiKey) {\n    vscode.window.showWarningMessage('Enter your API KEY to save it securely.');\n    apiKey = await setApiKey(context);\n    if (!apiKey) {\n      invokeLLMChunkCallback(lowcodeContext.webview, message.cbid, {\n        content: 'Please enter your api key',\n      });\n      return {\n        content: 'Please enter your api key',\n      };\n    }\n  }\n  const res = await createChatCompletion({\n    model: message.data.messages.some(\n      (s) =>\n        Array.isArray(s.content) &&\n        s.content.some((c) => c.type === 'image_url'),\n    )\n      ? 'gemini-pro-vision'\n      : 'gemini-pro',\n    apiKey,\n    messages: message.data.messages,\n    handleChunk: (data) => {\n      invokeLLMChunkCallback(lowcodeContext.webview, message.cbid, {\n        content: data.text,\n      });\n    },\n    proxyUrl: 'http://127.0.0.1:7890',\n  });\n  return {\n    content: res,\n  };\n};\n\nexport const askChatGPT = async (\n  message: IMessage<{\n    messages: Message;\n  }>,\n  lowcodeContext: {\n    webview: vscode.Webview;\n  } & CompileContext,\n) => {\n  const res = await createChatGPTChatCompletion({\n    model: message.data.messages.some(\n      (s) =>\n        Array.isArray(s.content) &&\n        s.content.some((c) => c.type === 'image_url'),\n    )\n      ? 'gpt-4-vision-preview'\n      : undefined,\n    messages: message.data.messages,\n    handleChunk: (data) => {\n      invokeLLMChunkCallback(lowcodeContext.webview, message.cbid, {\n        content: data.text,\n      });\n    },\n  });\n  return {\n    content: res,\n  };\n};\n\nasync function setApiKey(context) {\n  const apiKey = await vscode.window.showInputBox({\n    title: 'Enter your API KEY',\n    password: true,\n    placeHolder: '**************************************',\n    ignoreFocusOut: true,\n  });\n\n  if (!apiKey) {\n    vscode.window.showWarningMessage('Empty value');\n    return;\n  }\n\n  await context.secrets.store(API_KEY, apiKey);\n  return apiKey;\n}\n"
  },
  {
    "path": "materials/snippets/Pro Chat + Tldraw/script/src/main.ts",
    "content": "import { window } from 'vscode';\nimport { showWebView } from '@share/WebView';\nimport { routes } from './routes';\nimport { context } from './context';\n\nexport async function bootstrap() {\n  const { lowcodeContext } = context;\n  showWebView({\n    key: 'main',\n    title: 'tldraw make real',\n    viewColumn: 3,\n    task: {\n      task: 'route',\n      data: { path: '/tldraw', materialPath: lowcodeContext?.materialPath },\n    },\n    lowcodeContext: {\n      ...lowcodeContext!,\n    },\n    htmlForWebview: getHtmlForWebview(false),\n    routes,\n  });\n}\n\nconst getHtmlForWebview = (dev = false) => {\n  if (dev) {\n    return `\n\t\t\t\t<!doctype html>\n\t\t\t\t<html lang=\"en\">\n\t\t\t\t\t<head>\n\t\t\t\t\t\t<script type=\"module\">import { injectIntoGlobalHook } from \"http://127.0.0.1:5173/@react-refresh\";\n\t\t\t\t\t\tinjectIntoGlobalHook(window);\n\t\t\t\t\t\twindow.$RefreshReg$ = () => {};\n\t\t\t\t\t\twindow.$RefreshSig$ = () => (type) => type;</script>\n\n\t\t\t\t\t\t<script type=\"module\" src=\"http://127.0.0.1:5173/@vite/client\"></script>\n\t\t\t\t\t\t<script>\n\t\t\t\t\t\t\twindow.vscode = acquireVsCodeApi();\n\t\t\t\t\t\t</script>\n\t\t\t\t\t\t<meta charset=\"UTF-8\" />\n\t\t\t\t\t\t<link rel=\"icon\" type=\"image/svg+xml\" href=\"http://127.0.0.1:5173/vite.svg\" />\n\t\t\t\t\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n\t\t\t\t\t</head>\n\t\t\t\t\t<body>\n\t\t\t\t\t\t<div id=\"root\"></div>\n\t\t\t\t\t\t<script type=\"module\" src=\"http://127.0.0.1:5173/src/main.tsx\"></script>\n\t\t\t\t\t</body>\n\t\t\t\t</html>\n\t\t`;\n  }\n  return `\n\t\t\t<!DOCTYPE html>\n\t\t\t<html>\n\t\t\t<head>\n\t\t\t\t<meta charset=\"utf-8\" />\n\t\t\t\t<meta\n\t\t\t\t\tname=\"viewport\"\n\t\t\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no\"\n\t\t\t\t/>\n\t\t\t\t<script>\n\t\t\t\t   window.vscode = acquireVsCodeApi();\n        </script>\n\t\t\t\t<script type=\"module\" crossorigin src=\"http://lowcode-utools.oss-cn-beijing.aliyuncs.com/vscode.index.js\"></script>\n\t\t\t\t<link rel=\"stylesheet\" crossorigin href=\"http://lowcode-utools.oss-cn-beijing.aliyuncs.com/vscode.index.css\">\n\t\t\t</head>\n\t\t\t<body>\n\t\t\t\t<div id=\"root\"></div>\n\t\t\t</body>\n\t\t</html>\n`;\n};\n"
  },
  {
    "path": "materials/snippets/Pro Chat + Tldraw/script/src/routes.ts",
    "content": "import * as controller from './controller';\n\nexport const routes: Record<string, any> = {\n  getMaterialPath: controller.getMaterialPath,\n  askGemini: controller.askGemini,\n  askChatGPT: controller.askChatGPT,\n};\n"
  },
  {
    "path": "materials/snippets/Pro Chat + TypeChat/config/commandPrompt.ejs",
    "content": "export const <%- rawSelectedText %>Options = <%- content %>\n\nexport const <%- rawSelectedText %>Map = <%- rawSelectedText %>Options.reduce((obj, { label, value }) => {\n  obj[value] = label\n  return obj\n}, {})\n"
  },
  {
    "path": "materials/snippets/Pro Chat + TypeChat/config/model.json",
    "content": "{\n  \"name\": \"lowcode\"\n}"
  },
  {
    "path": "materials/snippets/Pro Chat + TypeChat/config/preview.json",
    "content": "{\n\t\"title\": \"\",\n\t\"description\": \"\",\n\t\"img\": [\n\t\t\"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n\t],\n\t\"category\": [],\n\t\"notShowInCommand\": true,\n\t\"notShowInSnippetsList\": true,\n\t\"notShowInintellisense\": true,\n\t\"showInRunSnippetScript\": true,\n\t\"schema\": \"amis\",\n\t\"scripts\": []\n}"
  },
  {
    "path": "materials/snippets/Pro Chat + TypeChat/config/schema.json",
    "content": "{\n  \"formSchema\": {\n    \"schema\": {\n      \"type\": \"page\",\n      \"body\": [\n        {\n          \"type\": \"form\",\n          \"title\": \"\",\n          \"body\": [\n            {\n              \"type\": \"input-text\",\n              \"name\": \"name\",\n              \"label\": \"测试表单\",\n              \"id\": \"u:4886baa626cf\",\n              \"value\": \"\"\n            }\n          ],\n          \"id\": \"u:67967afb0e69\",\n          \"submitText\": \"\"\n        }\n      ],\n      \"id\": \"u:d87dbf6bf8df\",\n      \"asideResizor\": false,\n      \"style\": {\n        \"boxShadow\": \" 0px 0px 0px 0px transparent\"\n      },\n      \"pullRefresh\": {\n        \"disabled\": true\n      },\n      \"regions\": [\n        \"body\"\n      ]\n    }\n  }\n}"
  },
  {
    "path": "materials/snippets/Pro Chat + TypeChat/config/schema.ts",
    "content": "export type IOption = { value: string; label: string }[];\n"
  },
  {
    "path": "materials/snippets/Pro Chat + TypeChat/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/Pro Chat + TypeChat/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/Pro Chat + TypeChat/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: (lowcodeContext) => {},\n  onSelect: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    await main.bootstrap();\n  },\n};\n"
  },
  {
    "path": "materials/snippets/Pro Chat + TypeChat/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { CompileContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/Pro Chat + TypeChat/script/src/main.ts",
    "content": "import fs from 'fs';\nimport path from 'path';\nimport { env, window, Range } from 'vscode';\nimport { createChatCompletionShowWebView } from '@share/LLM';\nimport { translate } from '@share/TypeChatSlim/index';\nimport { getMaterial } from '@share/utils/material';\nimport { compile as compileEjs } from '@share/utils/ejs';\nimport { context } from './context';\n\nexport async function bootstrap() {\n  const { lowcodeContext } = context;\n  const schema = fs.readFileSync(\n    path.join(lowcodeContext!.materialPath, 'config/schema.ts'),\n    'utf8',\n  );\n  const clipboardText = await env.clipboard.readText();\n  const { selection, document } = window.activeTextEditor!;\n  const selectText = document.getText(selection).trim();\n  const template = getMaterial(lowcodeContext!.materialPath);\n  lowcodeContext?.outputChannel.appendLine(lowcodeContext!.materialPath);\n  const res = await translate({\n    schema,\n    typeName: 'IOption',\n    request:\n      (clipboardText || '').trim() ||\n      '客户验收状态:1.无需验收、2.待验收、3已验收',\n    createChatCompletion: (options: {\n      messages: any;\n      handleChunk?: ((data: { text?: string | undefined }) => void) | undefined;\n    }) =>\n      createChatCompletionShowWebView({\n        messages: options.messages,\n        lowcodeContext: lowcodeContext!,\n        htmlForWebview: getHtmlForWebview(false),\n        // llm: 'gemini',\n      }),\n    tryCount: 3,\n  });\n  if (res.success) {\n    const code = compileEjs(template!.commandPrompt, {\n      rawSelectedText: selectText,\n      content: JSON.stringify(res.data),\n    } as any);\n    window.activeTextEditor?.edit((editBuilder) => {\n      // editBuilder.replace(activeTextEditor.selection, content);\n      if (window.activeTextEditor?.selection.isEmpty) {\n        editBuilder.insert(window.activeTextEditor.selection.start, code);\n      } else {\n        editBuilder.replace(\n          new Range(\n            window.activeTextEditor!.selection.start,\n            window.activeTextEditor!.selection.end,\n          ),\n          code,\n        );\n      }\n    });\n  } else {\n    window.showErrorMessage(res.message);\n  }\n}\n\nconst getHtmlForWebview = (dev = false) => {\n  if (dev) {\n    return `\n\t\t\t\t<!doctype html>\n\t\t\t\t<html lang=\"en\">\n\t\t\t\t\t<head>\n\t\t\t\t\t\t<script type=\"module\">import { injectIntoGlobalHook } from \"http://127.0.0.1:5173/@react-refresh\";\n\t\t\t\t\t\tinjectIntoGlobalHook(window);\n\t\t\t\t\t\twindow.$RefreshReg$ = () => {};\n\t\t\t\t\t\twindow.$RefreshSig$ = () => (type) => type;</script>\n\n\t\t\t\t\t\t<script type=\"module\" src=\"http://127.0.0.1:5173/@vite/client\"></script>\n\t\t\t\t\t\t<script>\n\t\t\t\t\t\t\twindow.vscode = acquireVsCodeApi();\n\t\t\t\t\t\t</script>\n\t\t\t\t\t\t<meta charset=\"UTF-8\" />\n\t\t\t\t\t\t<link rel=\"icon\" type=\"image/svg+xml\" href=\"http://127.0.0.1:5173/vite.svg\" />\n\t\t\t\t\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n\t\t\t\t\t</head>\n\t\t\t\t\t<body>\n\t\t\t\t\t\t<div id=\"root\"></div>\n\t\t\t\t\t\t<script type=\"module\" src=\"http://127.0.0.1:5173/src/main.tsx\"></script>\n\t\t\t\t\t</body>\n\t\t\t\t</html>\n\t\t`;\n  }\n  return `\n\t\t\t<!DOCTYPE html>\n\t\t\t<html>\n\t\t\t<head>\n\t\t\t\t<meta charset=\"utf-8\" />\n\t\t\t\t<meta\n\t\t\t\t\tname=\"viewport\"\n\t\t\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no\"\n\t\t\t\t/>\n\t\t\t\t<script>\n\t\t\t\t   window.vscode = acquireVsCodeApi();\n        </script>\n\t\t\t\t<script type=\"module\" crossorigin src=\"http://lowcode-utools.oss-cn-beijing.aliyuncs.com/vscode.index.js\"></script>\n\t\t\t\t<link rel=\"stylesheet\" crossorigin href=\"http://lowcode-utools.oss-cn-beijing.aliyuncs.com/vscode.index.css\">\n\t\t\t</head>\n\t\t\t<body>\n\t\t\t\t<div id=\"root\"></div>\n\t\t\t</body>\n\t\t</html>\n`;\n};\n"
  },
  {
    "path": "materials/snippets/amis/config/model.json",
    "content": "{\n  \"name\": \"lowcode\"\n}"
  },
  {
    "path": "materials/snippets/amis/config/preview.json",
    "content": "{\n  \"title\": \"\",\n  \"description\": \"\",\n  \"img\": [\n    \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n  ],\n  \"category\": [],\n  \"notShowInCommand\": false,\n  \"notShowInSnippetsList\": false,\n  \"notShowInintellisense\": false,\n  \"schema\": \"amis\",\n  \"scripts\": [\n    {\n      \"method\": \"test\",\n      \"remark\": \"测试一下\"\n    }\n  ]\n}"
  },
  {
    "path": "materials/snippets/amis/config/schema.json",
    "content": "{\n  \"formSchema\": {\n    \"schema\": {\n      \"type\": \"page\",\n      \"body\": [\n        {\n          \"type\": \"form\",\n          \"title\": \"\",\n          \"body\": [\n            {\n              \"type\": \"input-text\",\n              \"name\": \"name\",\n              \"label\": \"测试表单\",\n              \"id\": \"u:4886baa626cf\",\n              \"value\": \"\"\n            }\n          ],\n          \"id\": \"u:67967afb0e69\",\n          \"submitText\": \"\"\n        }\n      ],\n      \"id\": \"u:d87dbf6bf8df\",\n      \"asideResizor\": false,\n      \"style\": {\n        \"boxShadow\": \" 0px 0px 0px 0px transparent\"\n      },\n      \"pullRefresh\": {\n        \"disabled\": true\n      },\n      \"regions\": [\n        \"body\"\n      ]\n    }\n  }\n}"
  },
  {
    "path": "materials/snippets/amis/config/viewPrompt.ejs",
    "content": "<%- model %> \n将这段 json 中，中文 key 翻译为英文，\n使用驼峰语法，返回翻译后的 markdown 语法的代码块"
  },
  {
    "path": "materials/snippets/amis/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/amis/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/amis/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (context) => {\n    context.outputChannel.appendLine('compile amis start');\n  },\n  afterCompile: (context) => {\n    context.outputChannel.appendLine('compile amis end');\n  },\n  test: (context) => {\n    context.outputChannel.appendLine(Object.keys(context));\n    context.outputChannel.appendLine(JSON.stringify(context.model));\n    context.outputChannel.appendLine(context.params);\n    return { ...context.model, name: '测试一下' };\n  },\n};\n"
  },
  {
    "path": "materials/snippets/amis/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { CompileContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/amis/script/src/main.ts",
    "content": "export const main = 1;\n"
  },
  {
    "path": "materials/snippets/amis/src/template.ejs",
    "content": "<%= name %>"
  },
  {
    "path": "materials/snippets/axios-request/config/model.json",
    "content": "{}"
  },
  {
    "path": "materials/snippets/axios-request/config/preview.json",
    "content": "{\n\t\"title\": \"axios-request\",\n\t\"description\": \"axios 通用封装\",\n\t\"img\": \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\",\n\t\"category\": [\n\t\t\"请求\"\n\t]\n}"
  },
  {
    "path": "materials/snippets/axios-request/config/schema.json",
    "content": "{}"
  },
  {
    "path": "materials/snippets/axios-request/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/axios-request/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/axios-request/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (context) => {},\n  afterCompile: (constext) => {},\n};\n"
  },
  {
    "path": "materials/snippets/axios-request/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { CompileContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/axios-request/script/src/main.ts",
    "content": "export const main = 1;\n"
  },
  {
    "path": "materials/snippets/axios-request/src/template.ejs",
    "content": "import axios, { AxiosRequestConfig } from \"axios\";\n\nconst instance = axios.create({\n  timeout: 30 * 1000,\n});\n\n// 请求拦截\ninstance.interceptors.request.use(\n  (config) => {\n    return config;\n  },\n  (error) => {\n    return Promise.reject(error);\n  },\n);\n\n// 响应拦截\ninstance.interceptors.response.use(\n  (res) => {\n    return Promise.resolve(res.data);\n  },\n  (error) => {\n    return Promise.reject(error);\n  },\n);\n\ntype Request = <T = unknown>(config: AxiosRequestConfig) => Promise<T>;\n\nexport const request = instance.request as Request;\n"
  },
  {
    "path": "materials/snippets/axios-request-api/config/model.json",
    "content": "{}"
  },
  {
    "path": "materials/snippets/axios-request-api/config/preview.json",
    "content": "{\n\t\"title\": \"axios-request-api\",\n\t\"description\": \"通过 yapi 接口信息生成接口请求方法\",\n\t\"img\": \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n}"
  },
  {
    "path": "materials/snippets/axios-request-api/config/schema.json",
    "content": "{}"
  },
  {
    "path": "materials/snippets/axios-request-api/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/axios-request-api/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/axios-request-api/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (context) => {},\n  afterCompile: (constext) => {},\n};\n"
  },
  {
    "path": "materials/snippets/axios-request-api/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { CompileContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/axios-request-api/script/src/main.ts",
    "content": "export const main = 1;\n"
  },
  {
    "path": "materials/snippets/axios-request-api/src/template.ejs",
    "content": "<%= type %>  \n<% if (api.req_query.length > 0 || api.req_params.length > 0 || api.query_path.params.length > 0) { %>\nexport interface I<%= rawSelectedText.slice(0, 1).toUpperCase() + rawSelectedText.slice(1) %>Params {\n<% api.req_query.map(query => { %><%= query.name %>: string;<% }) %>\n<% api.req_params.map(query => { %><%= query.name %>: string;<% }) %>\n<% api.query_path.params.map(query => { %><%= query.name %>: string;<% }) %>\n}\n<% } %> \n<% if (requestBodyType && api.req_body_other.indexOf('{}')<0) { %>\n<%= requestBodyType %> \n<% } %> \n\n/**\n* <%= api.title %> \n* /project/<%= api.project_id %>/interface/api/<%= api._id %> \n* @author <%= api.username %>  \n* \n<% if (api.req_query.length > 0 || api.req_params.length > 0 || api.query_path.params.length > 0) { -%>* @param {I<%= rawSelectedText.slice(0, 1).toUpperCase() + rawSelectedText.slice(1) %>Params} params<%- \"\\n\" %><% } _%>\n<% if (requestBodyType && api.req_body_other.indexOf('{}')<0) { -%>* @param {I<%= rawSelectedText.slice(0, 1).toUpperCase() + rawSelectedText.slice(1) %>Data} data<%- \"\\n\" %><% } _%>\n* @returns\n*/\nexport function <%= rawSelectedText %> (\n<% if (api.req_query.length>0 || api.req_params.length > 0 || api.query_path.params.length > 0) { %>\nparams: I<%= rawSelectedText.slice(0, 1).toUpperCase() + rawSelectedText.slice(1) %>Params,\n<% } _%>\n<% if (requestBodyType) { %> \ndata: I<%= rawSelectedText.slice(0, 1).toUpperCase() + rawSelectedText.slice(1) %>Data\n<% } %> \n) {\nreturn request<I<%= rawSelectedText.slice(0, 1).toUpperCase() + rawSelectedText.slice(1) %>Result>({\n\t    url: `<%= api.query_path.path.replace(/\\{/g,\"${params.\") %>`, \n\t\tmethod: '<%= api.method %>',\n\t\t<% if(api.req_query.length>0 || api.req_params.length > 0) { %>params,<% } _%>\n<% if (requestBodyType && api.req_body_other.indexOf('{}')<0) {%>data,<% } %> \n\t})\n}"
  },
  {
    "path": "materials/snippets/axios-request-api-外挂脚本/config/commandPrompt.ejs",
    "content": "<%- rawSelectedText || rawClipboardText %>\n解释这段代码的意思"
  },
  {
    "path": "materials/snippets/axios-request-api-外挂脚本/config/model.json",
    "content": "{\n  \"name\": \"lowcode\"\n}"
  },
  {
    "path": "materials/snippets/axios-request-api-外挂脚本/config/preview.json",
    "content": "{\n  \"title\": \"\",\n  \"description\": \"\",\n  \"img\": [\n    \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n  ],\n  \"category\": [],\n  \"notShowInCommand\": false,\n  \"notShowInSnippetsList\": false,\n  \"notShowInintellisense\": false,\n\t\"showInRunSnippetScript\": true,\n  \"schema\": \"amis\",\n  \"scripts\": [\n    {\n      \"method\": \"test\",\n      \"remark\": \"测试一下\"\n    }\n  ]\n}"
  },
  {
    "path": "materials/snippets/axios-request-api-外挂脚本/config/schema.json",
    "content": "{\n  \"formSchema\": {\n    \"schema\": {\n      \"type\": \"page\",\n      \"body\": [\n        {\n          \"type\": \"form\",\n          \"title\": \"\",\n          \"body\": [\n            {\n              \"type\": \"input-text\",\n              \"name\": \"name\",\n              \"label\": \"测试表单\",\n              \"id\": \"u:4886baa626cf\",\n              \"value\": \"\"\n            }\n          ],\n          \"id\": \"u:67967afb0e69\",\n          \"submitText\": \"\"\n        }\n      ],\n      \"id\": \"u:d87dbf6bf8df\",\n      \"asideResizor\": false,\n      \"style\": {\n        \"boxShadow\": \" 0px 0px 0px 0px transparent\"\n      },\n      \"pullRefresh\": {\n        \"disabled\": true\n      },\n      \"regions\": [\n        \"body\"\n      ]\n    }\n  }\n}"
  },
  {
    "path": "materials/snippets/axios-request-api-外挂脚本/config/viewPrompt.ejs",
    "content": "<%- model %> \n将这段 json 中，中文 key 翻译为英文，\n使用驼峰语法，返回翻译后的 markdown 语法的代码块"
  },
  {
    "path": "materials/snippets/axios-request-api-外挂脚本/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/axios-request-api-外挂脚本/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/axios-request-api-外挂脚本/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: (lowcodeContext) => {},\n  test: (lowcodeContext) => {\n    lowcodeContext.outputChannel.appendLine(Object.keys(lowcodeContext));\n    lowcodeContext.outputChannel.appendLine(\n      JSON.stringify(lowcodeContext.model),\n    );\n    lowcodeContext.outputChannel.appendLine(lowcodeContext.params);\n    return { ...lowcodeContext.model, name: '测试一下' };\n  },\n  onSelect: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    await main.bootstrap();\n  },\n};\n"
  },
  {
    "path": "materials/snippets/axios-request-api-外挂脚本/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { ViewCallContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: ViewCallContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/axios-request-api-外挂脚本/script/src/genCode/genCodeByYapi.ts",
    "content": "import { window, env } from 'vscode';\nimport { compile } from 'json-schema-to-typescript';\nimport strip from 'strip-comments';\nimport jsonminify from 'jsonminify';\nimport * as GenerateSchema from 'generate-schema';\nimport { compile as compileEjs, Model } from '../utils/ejs';\nimport { fetchApiDetailInfo } from '../utils/request';\nimport { getFuncNameAndTypeName, pasteToEditor } from '../utils/editor';\nimport { mockFromSchema } from '../utils/json';\nimport { getConfig } from '../utils/config';\nimport { getMaterial } from '../utils/material';\nimport { context } from '../context';\n\nexport const genCodeByYapi = async () => {\n  const domain = getConfig().yapi?.domain || '';\n  if (!domain.trim()) {\n    window.showErrorMessage('请配置yapi域名');\n    return;\n  }\n  const projectList = getConfig().yapi?.projects || [];\n  if (projectList.length === 0) {\n    window.showErrorMessage('请配置项目');\n  }\n  const rawClipboardText = await env.clipboard.readText();\n  if (!rawClipboardText) {\n    window.showErrorMessage('请复制 yapi 接口 id');\n    return;\n  }\n\n  const selectInfo = getFuncNameAndTypeName();\n  const result = await window.showQuickPick(\n    projectList.map((s) => s.name),\n    { placeHolder: '请选择项目' },\n  );\n  if (!result) {\n    return;\n  }\n\n  const project = projectList.find((s) => s.name === result);\n  const { lowcodeContext } = context;\n  const template = getMaterial(lowcodeContext!.materialPath);\n  try {\n    const model = await genTemplateModelByYapi(\n      project?.domain || domain,\n      rawClipboardText,\n      project!.token,\n      selectInfo.typeName,\n      selectInfo.funcName,\n    );\n    if (model) {\n      model.rawSelectedText = selectInfo.rawSelectedText;\n      model.rawClipboardText = rawClipboardText;\n      const code = compileEjs(template!.template, model);\n      pasteToEditor(code);\n    }\n  } catch (e: any) {\n    window.showErrorMessage(e.toString());\n  }\n};\n\nconst genTemplateModelByYapi = async (\n  domain: string,\n  yapiId: string,\n  token: string,\n  typeNameOriginal: string,\n  funcNameOriginal: string,\n) => {\n  let funcName = funcNameOriginal;\n  let typeName = typeNameOriginal;\n  const res = await fetchApiDetailInfo(domain, yapiId, token);\n  if (!res.data.data) {\n    throw res.data.errmsg;\n  }\n  funcName = await context.lowcodeContext!.createChatCompletion({\n    messages: [\n      {\n        role: 'system',\n        content: `你是一个代码专家，按照用户传给你的 api 接口地址，和接口请求方法，根据接口地址里的信息推测出一个生动形象的方法名称，驼峰格式，返回方法名称`,\n      },\n      {\n        role: 'user',\n        content: `api 地址：${res.data.data.query_path}，${res.data.data.method} 方法，作用是${res.data.data.title}`,\n      },\n    ],\n  });\n  typeName = `I${funcName.charAt(0).toUpperCase() + funcName.slice(1)}Result`;\n  const requestBodyTypeName =\n    funcName.slice(0, 1).toUpperCase() + funcName.slice(1);\n  if (res.data.data.res_body_type === 'json') {\n    const schema = JSON.parse(jsonminify(res.data.data.res_body));\n    fixSchema(schema, ['$ref', '$$ref']);\n    delete schema.title;\n    let ts = await compile(schema, typeName, {\n      bannerComment: '',\n    });\n    ts = ts.replace(/(\\[k: string\\]: unknown;)|\\?/g, '');\n    const { mockCode, mockData } = mockFromSchema(schema);\n    let requestBodyType = '';\n    if (res.data.data.req_body_other) {\n      const reqBodyScheme = JSON.parse(res.data.data.req_body_other);\n      fixSchema(reqBodyScheme, ['$ref', '$$ref']);\n      delete reqBodyScheme.title;\n      requestBodyType = await compile(\n        reqBodyScheme,\n        `I${requestBodyTypeName}Data`,\n        {\n          bannerComment: '',\n        },\n      );\n    }\n    const model: Model = {\n      type: ts,\n      requestBodyType: requestBodyType.replace(/\\[k: string\\]: unknown;/g, ''),\n      funcName,\n      typeName,\n      api: res.data.data,\n      yapiDomain: domain,\n      inputValues: [],\n      mockCode,\n      mockData,\n      jsonData: {},\n      rawSelectedText: '',\n      rawClipboardText: '',\n    };\n    return model;\n  }\n  // yapi 返回数据直接贴的 json\n  const resBodyJson = JSON.parse(jsonminify(res.data.data.res_body));\n  const schema = GenerateSchema.json(typeName || 'Schema', resBodyJson);\n  fixSchema(schema, ['$ref', '$$ref']);\n  let ts = await compile(schema, typeName, {\n    bannerComment: '',\n  });\n  ts = strip(ts.replace(/(\\[k: string\\]: unknown;)|\\?/g, ''));\n  const { mockCode, mockData } = mockFromSchema(schema);\n  let requestBodyType = '';\n  if (res.data.data.req_body_other) {\n    const reqBodyScheme = JSON.parse(jsonminify(res.data.data.req_body_other));\n    fixSchema(reqBodyScheme, ['$ref', '$$ref']);\n    delete reqBodyScheme.title;\n    requestBodyType = await compile(\n      reqBodyScheme,\n      `I${requestBodyTypeName}Data`,\n      {\n        bannerComment: '',\n      },\n    );\n  }\n  const model: Model = {\n    type: ts,\n    requestBodyType: requestBodyType.replace(/\\[k: string\\]: unknown;/g, ''),\n    funcName,\n    typeName,\n    api: res.data.data,\n    yapiDomain: domain,\n    inputValues: [],\n    mockCode,\n    mockData,\n    jsonData: resBodyJson,\n    rawClipboardText: '',\n    rawSelectedText: '',\n  };\n  return model;\n};\n\nfunction fixSchema(obj: object, fieldNames: string[]) {\n  // eslint-disable-next-line no-restricted-syntax\n  for (const key in obj) {\n    if (Array.isArray(obj[key])) {\n      obj[key].forEach((item: object) => {\n        if (typeof item === 'object' && item !== null) {\n          fixSchema(item, fieldNames);\n        } else {\n          // eslint-disable-next-line no-restricted-syntax\n          for (const fieldName of fieldNames) {\n            if (item && item[fieldName]) {\n              delete item[fieldName];\n            }\n          }\n        }\n      });\n    } else if (typeof obj[key] === 'object' && obj[key] !== null) {\n      if (obj[key].type === 'object' && !obj[key].properties) {\n        delete obj[key];\n      }\n      fixSchema(obj[key], fieldNames);\n    } else {\n      // eslint-disable-next-line no-restricted-syntax\n      for (const fieldName of fieldNames) {\n        if (key === fieldName) {\n          delete obj[key];\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "materials/snippets/axios-request-api-外挂脚本/script/src/main.ts",
    "content": "import { genCodeByYapi } from './genCode/genCodeByYapi';\n\nexport async function bootstrap() {\n  await genCodeByYapi();\n}\n"
  },
  {
    "path": "materials/snippets/axios-request-api-外挂脚本/script/src/utils/config.ts",
    "content": "import * as path from 'path';\nimport * as fs from 'fs-extra';\nimport { workspace } from 'vscode';\nimport { getFileContent } from './file';\n\nconst defaultConfig: Config = {\n  yapi: { projects: [] },\n  mock: { mockKeyWordEqual: [], mockKeyWordLike: [] },\n  commonlyUsedBlock: [],\n};\n\nexport type Config = {\n  yapi?: {\n    domain?: string;\n    projects?: {\n      name: string;\n      token: string;\n      domain: string;\n    }[];\n  };\n  mock?: {\n    mockNumber?: string;\n    mockBoolean?: string;\n    mockString?: string;\n    mockKeyWordEqual?: {\n      key: string;\n      value: string;\n    }[];\n    mockKeyWordLike?: {\n      key: string;\n      value: string;\n    }[];\n  };\n  commonlyUsedBlock?: string[];\n};\n\nexport const getConfig: () => Config = () => {\n  let config: Config = {};\n  if (fs.existsSync(path.join(workspace.rootPath || '', '.lowcoderc'))) {\n    config = JSON.parse(getFileContent('.lowcoderc') || '{}');\n    config.yapi?.projects?.forEach((s) => {\n      s.domain = s.domain || config.yapi?.domain || '';\n    });\n  }\n  return { ...defaultConfig, ...config };\n};\n"
  },
  {
    "path": "materials/snippets/axios-request-api-外挂脚本/script/src/utils/editor.ts",
    "content": "import { Range, SnippetString, window } from 'vscode';\n\nexport const getSelectedText = () => {\n  const { selection, document } = window.activeTextEditor!;\n  return document.getText(selection).trim();\n};\n\nexport const pasteToEditor = (content: string, isInsertSnippet = true) => {\n  // vscode 本身代码片段语法\n  if (isInsertSnippet) {\n    return insertSnippet(content);\n  }\n  const { activeTextEditor } = window;\n  if (activeTextEditor === undefined) {\n    throw new Error('无打开文件');\n  }\n  return activeTextEditor?.edit((editBuilder) => {\n    // editBuilder.replace(activeTextEditor.selection, content);\n    if (activeTextEditor.selection.isEmpty) {\n      editBuilder.insert(activeTextEditor.selection.start, content);\n    } else {\n      editBuilder.replace(\n        new Range(\n          activeTextEditor.selection.start,\n          activeTextEditor.selection.end,\n        ),\n        content,\n      );\n    }\n  });\n};\n\nexport const insertSnippet = (content: string) => {\n  const { activeTextEditor } = window;\n  if (activeTextEditor === undefined) {\n    throw new Error('无打开文件');\n  }\n  return activeTextEditor.insertSnippet(new SnippetString(content));\n};\n\nexport const getFuncNameAndTypeName = () => {\n  // 这部分代码可以写在模版里，暂时保留\n  const selectedText = getSelectedText() || '';\n  let funcName = 'fetch';\n  let typeName = 'IFetchResult';\n  if (selectedText) {\n    const splitValue = selectedText.split(' ');\n    funcName = splitValue[0] || funcName;\n    if (splitValue.length > 1 && splitValue[1]) {\n      // eslint-disable-next-line prefer-destructuring\n      typeName = splitValue[1];\n    } else {\n      typeName = `I${\n        funcName.charAt(0).toUpperCase() + funcName.slice(1)\n      }Result`;\n    }\n  }\n  return {\n    funcName,\n    typeName,\n    rawSelectedText: selectedText,\n  };\n};\n"
  },
  {
    "path": "materials/snippets/axios-request-api-外挂脚本/script/src/utils/ejs.ts",
    "content": "import * as ejs from 'ejs';\n\nexport type YapiInfo = {\n  query_path: { path: string };\n  method: string;\n  title: string;\n  project_id: number;\n  req_params: {\n    name: string;\n    desc: string;\n  }[];\n  _id: number;\n  req_query: { required: '0' | '1'; name: string }[];\n  res_body_type: 'raw' | 'json';\n  res_body: string;\n  username: string;\n};\n\nexport type Model = {\n  type: string;\n  requestBodyType?: string;\n  funcName: string;\n  typeName: string;\n  inputValues: string[];\n  api?: YapiInfo;\n  yapiDomain?: string;\n  mockCode: string;\n  mockData: string;\n  jsonData: any;\n  jsonKeys?: string[];\n  rawSelectedText: string; // 编辑器中选中的原始文本\n  rawClipboardText: string; // 系统剪切板中的原始文本\n  activeTextEditorFilePath?: string; // 当前打开文件地址\n  createBlockPath?: string; // 创建区块的目录\n};\n\nexport const compile = (templateString: string, model: Model) =>\n  ejs.render(templateString, model);\n"
  },
  {
    "path": "materials/snippets/axios-request-api-外挂脚本/script/src/utils/file.ts",
    "content": "import * as path from 'path';\nimport * as fs from 'fs';\nimport { workspace } from 'vscode';\n\nexport const getFileContent = (filePath: string, fullPath = false) => {\n  let fileContent = '';\n  const fileFullPath = fullPath\n    ? filePath\n    : path.join(workspace.rootPath || '', filePath);\n  try {\n    const fileBuffer = fs.readFileSync(fileFullPath);\n    fileContent = fileBuffer.toString();\n    // eslint-disable-next-line no-empty\n  } catch (error) {}\n  return fileContent;\n};\n"
  },
  {
    "path": "materials/snippets/axios-request-api-外挂脚本/script/src/utils/json.ts",
    "content": "import { getConfig } from './config';\n\nexport const mockFromSchema = (schema: any) => {\n  let listIndex = 1;\n  const config = getConfig();\n  const mockConfig = config.mock;\n\n  const getMockValue = (key: string, defaultValue: string, type = 'number') => {\n    const value = defaultValue;\n    const mockKeyWordEqualConfig = mockConfig?.mockKeyWordEqual || [];\n    for (let i = 0; i < mockKeyWordEqualConfig.length; i++) {\n      if (key.toUpperCase() === mockKeyWordEqualConfig[i].key.toUpperCase()) {\n        if (typeof mockKeyWordEqualConfig[i].value === 'string') {\n          const array = mockKeyWordEqualConfig[i].value.split('&&');\n          if (array.length > 1) {\n            if (type === array[1]) {\n              return array[0];\n            }\n            return value;\n          }\n        }\n        return mockKeyWordEqualConfig[i].value;\n      }\n    }\n    const mockKeyWordLikeConfig = mockConfig?.mockKeyWordLike || [];\n    for (let i = 0; i < mockKeyWordLikeConfig.length; i++) {\n      if (\n        key.toUpperCase().indexOf(mockKeyWordLikeConfig[i].key.toUpperCase()) >\n        -1\n      ) {\n        if (typeof mockKeyWordLikeConfig[i].value === 'string') {\n          const array = mockKeyWordLikeConfig[i].value.split('&&');\n          if (array.length > 1) {\n            if (type === array[1]) {\n              return array[0];\n            }\n            return value;\n          }\n        }\n        return mockKeyWordLikeConfig[i].value;\n      }\n    }\n\n    return value;\n  };\n\n  const formatProperty = (property: any, key: string = '') => {\n    let jsonStr = '';\n    let listStr: string[] = [];\n    if (property.type === 'object') {\n      jsonStr += `${key ? `${key}: {` : ''}`;\n      Object.keys(property.properties).map((childPropertyKey) => {\n        const childProperty = property.properties[childPropertyKey];\n        const { jsonStr: childJsonStr, listStr: childListStr } = formatProperty(\n          childProperty,\n          childPropertyKey,\n        );\n        jsonStr += childJsonStr;\n        listStr = listStr.concat(childListStr);\n      });\n      jsonStr += `${key ? '},' : ''}`;\n    } else if (property.type === 'array') {\n      if (Object.keys(property.items).length > 0) {\n        const index = listIndex;\n        listIndex++;\n        let itemStr = `\n\t\t\t const list${index}=[];\n\t\t\t for(let i = 0; i < 10 ; i++){\n\t\t\t  list${index}.push(\n\t\t  `;\n        if (property.items.type === 'object') {\n          itemStr += '{';\n          Object.keys(property.items.properties).map((itemPropertyKey) => {\n            const itemProperty = property.items.properties[itemPropertyKey];\n            const { jsonStr: itemJsonStr, listStr: itemListStr } =\n              formatProperty(itemProperty, itemPropertyKey);\n            itemStr += itemJsonStr;\n            listStr = listStr.concat(itemListStr);\n          });\n          itemStr += `})}`;\n        } else {\n          if (property.items.type === 'string') {\n            itemStr += getMockValue(\n              key,\n              mockConfig?.mockString || '',\n              'string',\n            );\n          } else {\n            itemStr += getMockValue(\n              key,\n              mockConfig?.mockNumber || 'Random.natural(1000,1000)',\n            );\n          }\n          itemStr += `)}`;\n        }\n        listStr.push(itemStr);\n        jsonStr += `${key}: list${index},`;\n      } else {\n        jsonStr += `${key}: [],`;\n      }\n    } else if (property.type === 'number') {\n      jsonStr += `${key}: ${getMockValue(\n        key,\n        mockConfig?.mockNumber || 'Random.natural(1000,1000)',\n      )},`;\n    } else if (property.type === 'boolean') {\n      jsonStr += `${key}: ${getMockValue(\n        key,\n        mockConfig?.mockBoolean || 'false',\n        'boolean',\n      )},`;\n    } else if (property.type === 'string') {\n      jsonStr += `${key}: ${getMockValue(\n        key,\n        mockConfig?.mockString || 'Random.cword(5, 7)',\n        'string',\n      )},`;\n    }\n    return {\n      jsonStr,\n      listStr,\n    };\n  };\n  const { jsonStr, listStr } = formatProperty(schema);\n  return {\n    mockCode: listStr.join('\\n'),\n    mockData: `{${jsonStr}}`,\n  };\n};\n"
  },
  {
    "path": "materials/snippets/axios-request-api-外挂脚本/script/src/utils/material.ts",
    "content": "import * as path from 'path';\nimport { getFileContent } from './file';\n\nexport const getMaterial = (materialPath: string) => {\n  let material: {\n    model: object;\n    schema: object;\n    preview: {\n      title?: string;\n      description?: string;\n      img?: string | string[];\n      category?: string[];\n      notShowInCommand?: boolean;\n      notShowInSnippetsList?: boolean;\n      notShowInintellisense?: boolean;\n      schema?: string;\n      scripts?: [{ method: string; remark: string }];\n    };\n    template: string;\n    commandPrompt: string;\n    viewPrompt: string;\n  } = {} as any;\n  try {\n    const fullPath = path.join(materialPath);\n    let model = {} as any;\n    let schema = {} as any;\n    let preview = {\n      img: '',\n      category: [],\n      schema: 'form-render',\n      chatGPT: { commandPrompt: '', viewPrompt: '' },\n    };\n    let template = '';\n    let commandPrompt = '';\n    let viewPrompt = '';\n    try {\n      model = JSON.parse(\n        getFileContent(path.join(fullPath, 'config', 'model.json'), true),\n      );\n    } catch {}\n    try {\n      schema = JSON.parse(\n        getFileContent(path.join(fullPath, 'config', 'schema.json'), true),\n      );\n    } catch {}\n    try {\n      preview = JSON.parse(\n        getFileContent(path.join(fullPath, 'config', 'preview.json'), true),\n      );\n    } catch {}\n    try {\n      commandPrompt = getFileContent(\n        path.join(fullPath, 'config', 'commandPrompt.ejs'),\n        true,\n      );\n    } catch {}\n    try {\n      viewPrompt = getFileContent(\n        path.join(fullPath, 'config', 'viewPrompt.ejs'),\n        true,\n      );\n    } catch {}\n    if (!preview.img) {\n      preview.img =\n        'https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg';\n    }\n    if (!preview.schema) {\n      preview.schema = 'form-render';\n    }\n\n    try {\n      template = getFileContent(\n        path.join(fullPath, 'src', 'template.ejs'),\n        true,\n      );\n    } catch {}\n    if (schema.formSchema) {\n      if (schema.formSchema.formData) {\n        model = schema.formSchema.formData;\n      }\n      schema = schema.formSchema.schema;\n    }\n    if (Object.keys(schema).length > 0 && preview.schema === 'amis') {\n      // 设置 page 默认 name\n      schema.name = 'page';\n      if (schema.body && Array.isArray(schema.body)) {\n        schema.body.forEach((s: Record<string, unknown>) => {\n          if (s.type === 'form') {\n            s.name = 'form';\n            if (s.data && Object.keys(model).length === 0) {\n              model = s.data;\n            } else if (!s.data && Object.keys(model).length > 0) {\n              s.data = model;\n            }\n          }\n        });\n      }\n    }\n    material = {\n      model,\n      schema,\n      preview,\n      template,\n      commandPrompt,\n      viewPrompt,\n    };\n  } catch {}\n  return material;\n};\n"
  },
  {
    "path": "materials/snippets/axios-request-api-外挂脚本/script/src/utils/request.ts",
    "content": "import axios from 'axios';\n\nconst https = require('https');\n\nconst agent = new https.Agent({\n  rejectUnauthorized: true,\n});\n\nhttps.globalAgent.options.rejectUnauthorized = false;\n\ninterface IApiDetailInfo {\n  data: {\n    query_path: { path: string };\n    path: string;\n    method: string;\n    title: string;\n    project_id: number;\n    req_params: {\n      name: string;\n      desc: string;\n    }[];\n    _id: number;\n    req_query: { required: '0' | '1'; name: string }[];\n    res_body_type: 'raw' | 'json';\n    res_body: string;\n    req_body_other: string;\n    username: string;\n  };\n  errmsg?: string;\n}\n\nexport const fetchApiDetailInfo = (\n  domain: string,\n  id: string,\n  token: string,\n) => {\n  const url = domain.endsWith('/')\n    ? `${domain}api/interface/get?id=${id}&token=${token}`\n    : `${domain}/api/interface/get?id=${id}&token=${token}`;\n  return axios.get<IApiDetailInfo>(url, { httpsAgent: agent });\n};\n"
  },
  {
    "path": "materials/snippets/axios-request-api-外挂脚本/src/template.ejs",
    "content": "// #region <%= api.title %> \n<%- type %>  \n<% if (api.req_query.length > 0 || api.req_params.length > 0 || api.query_path.params.length > 0) { %>\nexport interface I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Params {\n<% api.req_query.map(query => { %><%= query.name %>: string;<% }) %>\n<% api.req_params.map(query => { %><%= query.name %>: string;<% }) %>\n<% api.query_path.params.map(query => { %><%= query.name %>: string;<% }) %>\n}\n<% } %> \n<% if (requestBodyType && api.req_body_other.indexOf('{}')<0) { %>\n<%- requestBodyType %> \n<% } %> \n\n/**\n* <%= api.title %> \n* <%= yapiDomain %>/project/<%= api.project_id %>/interface/api/<%= api._id %> \n* @author <%= api.username %>  \n* \n<% if (api.req_query.length > 0 || api.req_params.length > 0 || api.query_path.params.length > 0) { -%>* @param {I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Params} params<%- \"\\n\" %><% } _%>\n<% if (requestBodyType && api.req_body_other.indexOf('{}')<0) { -%>* @param {I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Data} data<%- \"\\n\" %><% } _%>\n* @returns\n*/\nexport function <%= funcName %> (\n<% if (api.req_query.length>0 || api.req_params.length > 0 || api.query_path.params.length > 0) { %>\nparams: I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Params,\n<% } _%>\n<% if (requestBodyType) { %> \ndata: I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Data\n<% } %> \n) {\nreturn request<I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Result>({\n\t    url: `<%= api.query_path.path.replace(/\\{/g,\"${params.\") %>`, \n\t\tmethod: '<%= api.method %>',\n\t\t<% if(api.req_query.length>0 || api.req_params.length > 0) { %>params,<% } _%>\n<% if (requestBodyType && api.req_body_other.indexOf('{}')<0) {%>data,<% } %> \n\t})\n}\n// #endregion"
  },
  {
    "path": "materials/snippets/form-render/config/model.json",
    "content": "{\n  \"name\": \"lowcode\"\n}"
  },
  {
    "path": "materials/snippets/form-render/config/preview.json",
    "content": "{\n  \"title\": \"\",\n  \"description\": \"\",\n  \"img\": [\n    \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n  ],\n  \"category\": [],\n  \"notShowInCommand\": false,\n  \"notShowInSnippetsList\": false,\n  \"notShowInintellisense\": false,\n  \"schema\": \"form-render\",\n  \"scripts\": [\n    {\n      \"method\": \"test\",\n      \"remark\": \"测试一下\"\n    }\n  ]\n}"
  },
  {
    "path": "materials/snippets/form-render/config/schema.json",
    "content": "{\n\t\"formSchema\": {\n\t\t\"schema\": {\n\t\t\t\"type\": \"object\",\n\t\t\t\"column\": 1,\n\t\t\t\"displayType\": \"column\",\n\t\t\t\"properties\": {\n\t\t\t\t\"name\": {\n\t\t\t\t\t\"title\": \"测试表单\",\n\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\"props\": {}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "materials/snippets/form-render/config/viewPrompt.ejs",
    "content": "<%- model %> \n将这段 json 中，中文 key 翻译为英文，\n使用驼峰语法，返回翻译后的 markdown 语法的代码块"
  },
  {
    "path": "materials/snippets/form-render/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/form-render/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/form-render/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (context) => {\n    context.outputChannel.appendLine('compile form-render start');\n  },\n  afterCompile: (context) => {\n    context.outputChannel.appendLine('compile form-render end');\n  },\n  test: (context) => {\n    context.outputChannel.appendLine(Object.keys(context));\n    context.outputChannel.appendLine(JSON.stringify(context.model));\n    context.outputChannel.appendLine(context.params);\n    return { ...context.model, name: '测试一下' };\n  },\n};\n"
  },
  {
    "path": "materials/snippets/form-render/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { CompileContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/form-render/script/src/main.ts",
    "content": "export const main = 1;\n"
  },
  {
    "path": "materials/snippets/form-render/src/template.ejs",
    "content": "<%= name %>"
  },
  {
    "path": "materials/snippets/formily/config/model.json",
    "content": "{\n  \"name\": \"lowcode\"\n}"
  },
  {
    "path": "materials/snippets/formily/config/preview.json",
    "content": "{\n  \"title\": \"\",\n  \"description\": \"\",\n  \"img\": [\n    \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n  ],\n  \"category\": [],\n  \"notShowInCommand\": false,\n  \"notShowInSnippetsList\": false,\n  \"notShowInintellisense\": false,\n  \"schema\": \"formily\",\n  \"scripts\": [\n    {\n      \"method\": \"test\",\n      \"remark\": \"测试一下\"\n    }\n  ]\n}"
  },
  {
    "path": "materials/snippets/formily/config/schema.json",
    "content": "{\n\t\"formSchema\": {\n\t\t\"schema\": {\n\t\t\t\"form\": {\n\t\t\t\t\"labelCol\": 6,\n\t\t\t\t\"wrapperCol\": 12,\n\t\t\t\t\"layout\": \"vertical\",\n\t\t\t\t\"labelAlign\": \"left\",\n\t\t\t\t\"fullness\": false,\n\t\t\t\t\"inset\": false\n\t\t\t},\n\t\t\t\"schema\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"title\": \"测试表单\",\n\t\t\t\t\t\t\"x-decorator\": \"FormItem\",\n\t\t\t\t\t\t\"x-component\": \"Input\",\n\t\t\t\t\t\t\"x-validator\": [],\n\t\t\t\t\t\t\"x-component-props\": {},\n\t\t\t\t\t\t\"x-decorator-props\": {},\n\t\t\t\t\t\t\"x-designable-id\": \"v3zwx2xtcfx\",\n\t\t\t\t\t\t\"x-index\": 0,\n\t\t\t\t\t\t\"name\": \"name\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"x-designable-id\": \"d4ogui2afmr\"\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "materials/snippets/formily/config/viewPrompt.ejs",
    "content": "<%- model %> \n将这段 json 中，中文 key 翻译为英文，\n使用驼峰语法，返回翻译后的 markdown 语法的代码块"
  },
  {
    "path": "materials/snippets/formily/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/formily/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/formily/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (context) => {\n    context.outputChannel.appendLine('compile formily start');\n  },\n  afterCompile: (context) => {\n    context.outputChannel.appendLine('compile formily end');\n  },\n  test: (context) => {\n    context.outputChannel.appendLine(Object.keys(context));\n    context.outputChannel.appendLine(JSON.stringify(context.model));\n    context.outputChannel.appendLine(context.params);\n    return { ...context.model, name: '测试一下' };\n  },\n};\n"
  },
  {
    "path": "materials/snippets/formily/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { CompileContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/formily/script/src/main.ts",
    "content": "export const main = 1;\n"
  },
  {
    "path": "materials/snippets/formily/src/template.ejs",
    "content": "<%= name %>"
  },
  {
    "path": "materials/snippets/share ChatGPT 测试/config/model.json",
    "content": "{\n  \"name\": \"lowcode\"\n}"
  },
  {
    "path": "materials/snippets/share ChatGPT 测试/config/preview.json",
    "content": "{\n\t\"title\": \"\",\n\t\"description\": \"\",\n\t\"img\": [\n\t\t\"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n\t],\n\t\"category\": [],\n\t\"notShowInCommand\": true,\n\t\"notShowInSnippetsList\": true,\n\t\"notShowInintellisense\": true,\n\t\"showInRunSnippetScript\": true,\n\t\"schema\": \"amis\",\n\t\"scripts\": []\n}"
  },
  {
    "path": "materials/snippets/share ChatGPT 测试/config/schema.json",
    "content": "{\n  \"formSchema\": {\n    \"schema\": {\n      \"type\": \"page\",\n      \"body\": [\n        {\n          \"type\": \"form\",\n          \"title\": \"\",\n          \"body\": [\n            {\n              \"type\": \"input-text\",\n              \"name\": \"name\",\n              \"label\": \"测试表单\",\n              \"id\": \"u:4886baa626cf\",\n              \"value\": \"\"\n            }\n          ],\n          \"id\": \"u:67967afb0e69\",\n          \"submitText\": \"\"\n        }\n      ],\n      \"id\": \"u:d87dbf6bf8df\",\n      \"asideResizor\": false,\n      \"style\": {\n        \"boxShadow\": \" 0px 0px 0px 0px transparent\"\n      },\n      \"pullRefresh\": {\n        \"disabled\": true\n      },\n      \"regions\": [\n        \"body\"\n      ]\n    }\n  }\n}"
  },
  {
    "path": "materials/snippets/share ChatGPT 测试/config/schema.ts",
    "content": "export type IColumns = {\n  /**\n   * @description 保持原始内容，不需要处理，不要翻译\n   * @type {string}\n   */\n  title: string;\n  /**\n   * @description 翻译成英文，驼峰格式\n   * @type {string}\n   */\n  dataIndex: string;\n  /**\n   * @description 翻译成英文，驼峰格式\n   * @type {string}\n   */\n  key: string;\n  slots: {\n    /**\n     * @description 翻译成英文，驼峰格式\n     * @type {string}\n     */\n    customRender: string;\n  };\n}[];\n"
  },
  {
    "path": "materials/snippets/share ChatGPT 测试/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/share ChatGPT 测试/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/share ChatGPT 测试/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: (lowcodeContext) => {},\n  onSelect: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    await main.bootstrap();\n  },\n};\n"
  },
  {
    "path": "materials/snippets/share ChatGPT 测试/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { CompileContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/share ChatGPT 测试/script/src/main.ts",
    "content": "import * as path from 'path';\nimport * as fs from 'fs-extra';\nimport { window, Range } from 'vscode';\nimport { generalBasic } from '@share/BaiduOCR/index';\nimport { translate } from '@share/TypeChatSlim/index';\nimport { createChatCompletion } from '@share/LLM/openai';\nimport { context } from './context';\nimport { IColumns } from '../../config/schema';\n\nconst systemPrompt = `# Role: Tailwind CSS Developer\n\n## Task\n\n- Input: Screenshot(s) of a reference web page or Low-fidelity\n- Output: Single HTML page using Tailwind CSS, HTML\n\n## Guidelines\n\n- Utilize Tailwind CSS to develop the website based on the provided screenshot or Low-fidelity\n- Achieve an exact visual match to the provided screenshot or Low-fidelity\n- Pay close attention to:\n  - Background color\n  - Text color\n  - Font size\n  - Font family\n  - Padding\n  - Margin\n  - Border\n- Use the precise text from the screenshot\n- Avoid placeholder comments; write the full code\n- Repeat elements as shown in the screenshot (e.g., if there are 15 items, include 15 items in the code)\n- Use placeholder images from \\`https://placehold.co\\` with descriptive \\`alt\\` text for future image generation\n\n## Libraries\n\n- Include Tailwind CSS via: \\`<script src=\"https://cdn.tailwindcss.com\"></script>\\`\n\n## Deliverable\n\n- Respond with the complete HTML code within \\`<html>\\` tags\n- Respond with the HTML file content only\n`;\n\nexport async function bootstrap() {\n  const { lowcodeContext } = context;\n  const res = await createChatCompletion({\n    model: 'gpt-4-vision-preview',\n    maxTokens: 4096,\n    messages: [\n      {\n        role: 'system',\n        content: systemPrompt,\n      },\n      {\n        role: 'user',\n        content: [\n          {\n            type: 'image_url',\n            image_url: { url: 'https://i.imgur.com/fHpqvC9.png' },\n          },\n          {\n            type: 'text',\n            text: 'Turn this into a single html file using tailwind.',\n          },\n        ],\n      },\n    ],\n    handleChunk(data) {\n      lowcodeContext?.log.append(data.text || '');\n    },\n  });\n}\n"
  },
  {
    "path": "materials/snippets/share ChatGPT 测试/src/template.ejs",
    "content": ""
  },
  {
    "path": "materials/snippets/start nest api server/config/commandPrompt.ejs",
    "content": "<%- rawSelectedText || rawClipboardText %>\n解释这段代码的意思"
  },
  {
    "path": "materials/snippets/start nest api server/config/model.json",
    "content": "{\n  \"name\": \"lowcode\"\n}"
  },
  {
    "path": "materials/snippets/start nest api server/config/preview.json",
    "content": "{\n  \"title\": \"\",\n  \"description\": \"\",\n  \"img\": [\n    \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n  ],\n  \"category\": [],\n  \"notShowInCommand\": false,\n  \"notShowInSnippetsList\": true,\n  \"notShowInintellisense\": true,\n\t\"showInRunSnippetScript\": true,\n  \"schema\": \"amis\",\n  \"scripts\": [\n    {\n      \"method\": \"test\",\n      \"remark\": \"测试一下\"\n    }\n  ]\n}"
  },
  {
    "path": "materials/snippets/start nest api server/config/schema.json",
    "content": "{\n  \"formSchema\": {\n    \"schema\": {\n      \"type\": \"page\",\n      \"body\": [\n        {\n          \"type\": \"form\",\n          \"title\": \"\",\n          \"body\": [\n            {\n              \"type\": \"input-text\",\n              \"name\": \"name\",\n              \"label\": \"测试表单\",\n              \"id\": \"u:4886baa626cf\",\n              \"value\": \"\"\n            }\n          ],\n          \"id\": \"u:67967afb0e69\",\n          \"submitText\": \"\"\n        }\n      ],\n      \"id\": \"u:d87dbf6bf8df\",\n      \"asideResizor\": false,\n      \"style\": {\n        \"boxShadow\": \" 0px 0px 0px 0px transparent\"\n      },\n      \"pullRefresh\": {\n        \"disabled\": true\n      },\n      \"regions\": [\n        \"body\"\n      ]\n    }\n  }\n}"
  },
  {
    "path": "materials/snippets/start nest api server/config/viewPrompt.ejs",
    "content": "<%- model %> \n将这段 json 中，中文 key 翻译为英文，\n使用驼峰语法，返回翻译后的 markdown 语法的代码块"
  },
  {
    "path": "materials/snippets/start nest api server/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/start nest api server/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/start nest api server/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {\n    lowcodeContext.outputChannel.appendLine(\n      'compile start nest api srver start',\n    );\n  },\n  afterCompile: (lowcodeContext) => {\n    lowcodeContext.outputChannel.appendLine('compile start nest api srver end');\n  },\n  test: (lowcodeContext) => {\n    lowcodeContext.outputChannel.appendLine(Object.keys(lowcodeContext));\n    lowcodeContext.outputChannel.appendLine(\n      JSON.stringify(lowcodeContext.model),\n    );\n    lowcodeContext.outputChannel.appendLine(lowcodeContext.params);\n    return { ...lowcodeContext.model, name: '测试一下' };\n  },\n  onSelect: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    await main.bootstrap();\n  },\n};\n"
  },
  {
    "path": "materials/snippets/start nest api server/script/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getMaterialPath() {\n    return this.appService.getMaterialPath();\n  }\n}\n"
  },
  {
    "path": "materials/snippets/start nest api server/script/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { ConfigModule } from '@nestjs/config';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\n\n@Module({\n  imports: [\n    ConfigModule.forRoot({\n      envFilePath: `.env.${process.env.NODE_ENV}`,\n      isGlobal: true,\n    }),\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "materials/snippets/start nest api server/script/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { context } from './context';\n\n@Injectable()\nexport class AppService {\n  getMaterialPath() {\n    return context.lowcodeContext?.materialPath;\n  }\n}\n"
  },
  {
    "path": "materials/snippets/start nest api server/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { ViewCallContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: ViewCallContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/start nest api server/script/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { context } from './context';\n\nexport async function bootstrap() {\n  const lowcodeContext = context.lowcodeContext!;\n  if (!context.statusBarItem) {\n    const statusBarItem = lowcodeContext.vscode.window.createStatusBarItem(\n      lowcodeContext.vscode.StatusBarAlignment.Left,\n    );\n    context.statusBarItem = statusBarItem;\n  }\n  if (!context.nestApp) {\n    context.statusBarItem.text = '$(loading~spin) Start nest api server...';\n    context.statusBarItem.show();\n    const app = await NestFactory.create(AppModule);\n    await app\n      .listen(3000)\n      .then(() => {\n        context.nestApp = app;\n        if (context.statusBarItem) {\n          context.statusBarItem.text =\n            '$(circle-slash) Low Code Server Port : 3000';\n          context.statusBarItem.tooltip = 'Click to close nest api server';\n          // vscode 限制命令唯一，但是唯一的话命令回调里的 context 永远是同一个\n          const command = `lowcode.StopNestApiServer${new Date().getTime()}`;\n          try {\n            const dsisposable = lowcodeContext.vscode.commands.registerCommand(\n              command,\n              () => {\n                context.statusBarItem!.text = '$(loading~spin) close...';\n                context.statusBarItem!.command = undefined;\n                context.nestApp?.close().then(() => {\n                  context.nestApp = undefined;\n                  context.statusBarItem?.hide();\n                  context.statusBarItem?.dispose();\n                  context.statusBarItem = undefined;\n                  dsisposable.dispose();\n                });\n              },\n            );\n          } catch (ex) {\n            /* empty */\n          }\n          context.statusBarItem.command = command;\n        }\n      })\n      .catch((ex) => {\n        context.statusBarItem?.hide();\n        context.statusBarItem?.dispose();\n        context.statusBarItem = undefined;\n        throw ex;\n      });\n  }\n}\n"
  },
  {
    "path": "materials/snippets/start nest api server/src/template.ejs",
    "content": "<%= name %>"
  },
  {
    "path": "materials/snippets/taro-request-api/config/model.json",
    "content": "{}"
  },
  {
    "path": "materials/snippets/taro-request-api/config/preview.json",
    "content": "{\n\t\"title\": \"taro-request-api\",\n\t\"description\": \"通过 yapi 接口信息生成接口请求方法\",\n\t\"img\": \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n}"
  },
  {
    "path": "materials/snippets/taro-request-api/config/schema.json",
    "content": "{}"
  },
  {
    "path": "materials/snippets/taro-request-api/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/taro-request-api/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/taro-request-api/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (context) => {},\n  afterCompile: (constext) => {},\n};\n"
  },
  {
    "path": "materials/snippets/taro-request-api/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { CompileContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/taro-request-api/script/src/main.ts",
    "content": "export const main = 1;\n"
  },
  {
    "path": "materials/snippets/taro-request-api/src/template.ejs",
    "content": "<%= type %>  \n<% if (api.req_query.length > 0 || api.req_params.length > 0 || api.query_path.params.length > 0) { %>\nexport interface I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Params {\n<% api.req_query.map(query => { %><%= query.name %>: string;<% }) %>\n<% api.req_params.map(query => { %><%= query.name %>: string;<% }) %>\n<% api.query_path.params.map(query => { %><%= query.name %>: string;<% }) %>\n}\n<% } %> \n<% if (requestBodyType && api.req_body_other.indexOf('{}')<0) { %>\n<%= requestBodyType %> \n<% } %> \n\n/**\n* <%= api.title %> \n* /project/<%= api.project_id %>/interface/api/<%= api._id %> \n* @author <%= api.username %>  \n* \n<% if (api.req_query.length > 0 || api.req_params.length > 0 || api.query_path.params.length > 0) { -%>* @param {I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Params} params<%- \"\\n\" %><% } _%>\n<% if (requestBodyType && api.req_body_other.indexOf('{}')<0) { -%>* @param {I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Data} data<%- \"\\n\" %><% } _%>\n* @returns\n*/\nexport function <%= funcName %> (\n<% if (api.req_query.length>0 || api.req_params.length > 0 || api.query_path.params.length > 0) { _%>\nparams: I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Params,\n<% } _%>\n<% if (requestBodyType && api.req_body_other.indexOf('{}')<0) { _%> \ndata: I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Data\n<% } _%> \n) {\nreturn request<<%= typeName %>>(`<%= api.query_path.path.replace(/\\{/g,\"${params.\") %>`, {\n\t\tmethod: '<%= api.method %>',\n\t\t<% if(api.req_query.length>0 || api.req_params.length > 0) { %>params,<% } _%>\n<% if (requestBodyType && api.req_body_other.indexOf('{}')<0) {%>data,<% } %> \n\t})\n}"
  },
  {
    "path": "materials/snippets/umi-request-api/config/model.json",
    "content": "{}"
  },
  {
    "path": "materials/snippets/umi-request-api/config/preview.json",
    "content": "{\n\t\"title\": \"umi-request-api\",\n\t\"description\": \"通过 yapi 接口信息生成接口请求方法\",\n\t\"img\": \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n}"
  },
  {
    "path": "materials/snippets/umi-request-api/config/schema.json",
    "content": "{}"
  },
  {
    "path": "materials/snippets/umi-request-api/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/umi-request-api/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/umi-request-api/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (context) => {},\n  afterCompile: (constext) => {},\n};\n"
  },
  {
    "path": "materials/snippets/umi-request-api/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { CompileContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/umi-request-api/script/src/main.ts",
    "content": "export const main = 1;\n"
  },
  {
    "path": "materials/snippets/umi-request-api/src/template.ejs",
    "content": "<%= type %>  \n<% if (api.req_query.length > 0 || api.req_params.length > 0 || api.query_path.params.length > 0) { %>\nexport interface I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Params {\n<% api.req_query.map(query => { %><%= query.name %>: string;<% }) %>\n<% api.req_params.map(query => { %><%= query.name %>: string;<% }) %>\n<% api.query_path.params.map(query => { %><%= query.name %>: string;<% }) %>\n}\n<% } %> \n<% if (requestBodyType && api.req_body_other.indexOf('{}')<0) { %>\n<%= requestBodyType %> \n<% } %> \n\n/**\n* <%= api.title %> \n* /project/<%= api.project_id %>/interface/api/<%= api._id %> \n* @author <%= api.username %>  \n* \n<% if (api.req_query.length > 0 || api.req_params.length > 0 || api.query_path.params.length > 0) { -%>* @param {I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Params} params<%- \"\\n\" %><% } _%>\n<% if (requestBodyType && api.req_body_other.indexOf('{}')<0) { -%>* @param {I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Data} data<%- \"\\n\" %><% } _%>\n* @returns\n*/\nexport function <%= funcName %> (\n<% if (api.req_query.length>0 || api.req_params.length > 0 || api.query_path.params.length > 0) { _%>\nparams: I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Params,\n<% } _%>\n<% if (requestBodyType && api.req_body_other.indexOf('{}')<0) { _%> \ndata: I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Data\n<% } _%> \n) {\nreturn request<<%= typeName %>>(`<%= api.query_path.path.replace(/\\{/g,\"${params.\") %>`, {\n\t\tmethod: '<%= api.method %>',\n\t\t<% if(api.req_query.length>0 || api.req_params.length > 0) { %>params,<% } _%>\n<% if (requestBodyType && api.req_body_other.indexOf('{}')<0) {%>data,<% } %> \n\t})\n}"
  },
  {
    "path": "materials/snippets/动态表单 demo/config/model.json",
    "content": "{\n  \"filters\": [],\n  \"columns\": [],\n  \"pagination\": {\n    \"show\": true,\n    \"page\": \"page\",\n    \"size\": \"size\",\n    \"total\": \"result.total\"\n  },\n  \"includeModifyModal\": false,\n  \"fetchName\": \"fetchTableList\",\n  \"result\": \"[\\\"result\\\"][\\\"records\\\"]\",\n  \"serviceName\": \"getTableList\"\n}\n"
  },
  {
    "path": "materials/snippets/动态表单 demo/config/preview.json",
    "content": "{\n  \"title\": \"\",\n  \"description\": \"\",\n  \"img\": [\n    \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n  ],\n  \"category\": [],\n  \"notShowInCommand\": true,\n  \"notShowInSnippetsList\": true,\n  \"notShowInintellisense\": true,\n  \"showInRunSnippetScript\": true,\n  \"showInRunSnippetScriptOnExplorer\": false,\n  \"runActivate\": false,\n  \"schema\": \"amis\",\n  \"scripts\": [\n    {\n      \"method\": \"initFiltersFromImage\",\n      \"remark\": \"使用 OCR 识别查询条件截图内容\"\n    },\n    {\n      \"method\": \"initFiltersFromText\",\n      \"remark\": \"使用文本初始化查询条件\"\n    },\n    {\n      \"method\": \"initColumnsFromText\",\n      \"remark\": \"使用文本初始化表格\"\n    },\n    {\n      \"method\": \"initColumnsFromImage\",\n      \"remark\": \"使用截图初始化表格\"\n    },\n    {\n      \"method\": \"askChatGPT\",\n      \"remark\": \"使用 ChatGPT 翻译模版数据里的指定中文字段\"\n    }\n  ]\n}\n"
  },
  {
    "path": "materials/snippets/动态表单 demo/config/schema.json",
    "content": "{\n  \"type\": \"page\",\n  \"body\": [\n    {\n      \"type\": \"form\",\n      \"title\": \"\",\n      \"body\": [\n        {\n          \"type\": \"combo\",\n          \"label\": \"查询条件\",\n          \"name\": \"filters\",\n          \"multiple\": true,\n          \"addable\": true,\n          \"removable\": true,\n          \"removableMode\": \"icon\",\n          \"addBtn\": {\n            \"label\": \"新增\",\n            \"icon\": \"fa fa-plus\",\n            \"level\": \"primary\",\n            \"size\": \"sm\",\n            \"id\": \"u:47ecb9e15ff1\"\n          },\n          \"items\": [\n            {\n              \"type\": \"input-text\",\n              \"name\": \"key\",\n              \"placeholder\": \"字段名\",\n              \"id\": \"u:25b0c7b5e5a0\",\n              \"label\": \"字段名（key）\"\n            },\n            {\n              \"type\": \"input-text\",\n              \"label\": \"label\",\n              \"name\": \"label\",\n              \"id\": \"u:6496cac4f4b8\",\n              \"description\": \"\"\n            },\n            {\n              \"type\": \"select\",\n              \"name\": \"component\",\n              \"placeholder\": \"选项\",\n              \"options\": [\n                {\n                  \"label\": \"input\",\n                  \"value\": \"input\"\n                },\n                {\n                  \"label\": \"select\",\n                  \"value\": \"select\"\n                }\n              ],\n              \"id\": \"u:995915eabcca\",\n              \"multiple\": false,\n              \"label\": \"组件\",\n              \"value\": \"\"\n            },\n            {\n              \"type\": \"input-text\",\n              \"label\": \"placeholder\",\n              \"name\": \"placeholder\",\n              \"id\": \"u:d7f1a8a39449\",\n              \"description\": \"\"\n            }\n          ],\n          \"id\": \"u:186f183e9320\",\n          \"strictMode\": false,\n          \"syncFields\": [],\n          \"tabsMode\": true,\n          \"draggable\": true,\n          \"draggableTip\": \"可拖动排序\",\n          \"tabsStyle\": \"line\",\n          \"tabsLabelTpl\": \"表单项${index+1}\",\n          \"multiLine\": true,\n          \"noBorder\": false\n        },\n        {\n          \"type\": \"combo\",\n          \"label\": \"表格\",\n          \"name\": \"columns\",\n          \"multiple\": true,\n          \"addable\": true,\n          \"removable\": true,\n          \"removableMode\": \"button\",\n          \"addBtn\": {\n            \"label\": \"新增\",\n            \"icon\": \"fa fa-plus\",\n            \"level\": \"primary\",\n            \"size\": \"sm\",\n            \"id\": \"u:1e8070edc3d3\"\n          },\n          \"items\": [\n            {\n              \"type\": \"input-text\",\n              \"name\": \"title\",\n              \"id\": \"u:152dd82b82f9\",\n              \"label\": \"title\"\n            },\n            {\n              \"type\": \"input-text\",\n              \"label\": \"dataIndex\",\n              \"name\": \"dataIndex\",\n              \"id\": \"u:ecc7298e0550\",\n              \"description\": \"\"\n            },\n            {\n              \"type\": \"input-text\",\n              \"label\": \"key\",\n              \"name\": \"key\",\n              \"id\": \"u:fbaa95c3f15d\",\n              \"description\": \"\"\n            },\n            {\n              \"type\": \"input-text\",\n              \"label\": \"width\",\n              \"name\": \"width\",\n              \"id\": \"u:b143127e097b\",\n              \"description\": \"\"\n            },\n            {\n              \"type\": \"switch\",\n              \"label\": \"自定义插槽\",\n              \"option\": \"\",\n              \"name\": \"slot\",\n              \"falseValue\": false,\n              \"trueValue\": true,\n              \"id\": \"u:ee1ce1faee0b\",\n              \"value\": false\n            }\n          ],\n          \"id\": \"u:9b9fb0cf38f9\",\n          \"strictMode\": true,\n          \"syncFields\": [],\n          \"tabsMode\": true,\n          \"draggable\": true,\n          \"draggableTip\": \"可拖动排序\",\n          \"tabsStyle\": \"line\",\n          \"deleteBtn\": {\n            \"label\": \"删除\",\n            \"level\": \"default\"\n          },\n          \"tabsLabelTpl\": \"列${index+1}\"\n        },\n        {\n          \"type\": \"fieldset\",\n          \"title\": \"分页参数\",\n          \"collapsable\": true,\n          \"body\": [\n            {\n              \"type\": \"switch\",\n              \"label\": \"是否分页\",\n              \"option\": \"\",\n              \"name\": \"pagination.show\",\n              \"falseValue\": false,\n              \"trueValue\": true,\n              \"id\": \"u:6c70041d5143\",\n              \"value\": true,\n              \"className\": \"\"\n            },\n            {\n              \"type\": \"input-text\",\n              \"label\": \"查询接口页数参数字段名\",\n              \"name\": \"pagination.page\",\n              \"id\": \"u:cbbf6853cf64\",\n              \"value\": \"page\"\n            },\n            {\n              \"type\": \"input-text\",\n              \"label\": \"查询接口每页数据行数参数字段名\",\n              \"name\": \"pagination.size\",\n              \"id\": \"u:a8fae66fa927\",\n              \"value\": \"size\"\n            },\n            {\n              \"type\": \"input-text\",\n              \"label\": \"接口返回总数据量字段 PATH\",\n              \"name\": \"pagination.total\",\n              \"id\": \"u:e1cd979c7ee8\",\n              \"value\": \"result.total\",\n              \"themeCss\": {\n                \"inputControlClassName\": {\n                  \"padding-and-margin:default\": {\n                    \"marginBottom\": \"\",\n                    \"marginTop\": \"\",\n                    \"marginRight\": \"\",\n                    \"marginLeft\": \"\"\n                  }\n                }\n              }\n            }\n          ],\n          \"id\": \"u:0f1bd8fc2f2b\",\n          \"collapsed\": true,\n          \"headingClassName\": \"\",\n          \"bodyClassName\": \"p\"\n        },\n        {\n          \"type\": \"fieldset\",\n          \"title\": \"请求方法\",\n          \"collapsable\": true,\n          \"body\": [\n            {\n              \"type\": \"input-text\",\n              \"label\": \"请求名称\",\n              \"name\": \"fetchName\",\n              \"id\": \"u:a3e712484fae\",\n              \"value\": \"fetchTableList\",\n              \"description\": \"追加了YAPI数据则不使用此参数\",\n              \"themeCss\": {\n                \"labelClassName\": {\n                  \"padding-and-margin:default\": {\n                    \"marginTop\": \"\",\n                    \"marginRight\": \"\",\n                    \"marginBottom\": \"\",\n                    \"marginLeft\": \"\"\n                  }\n                }\n              },\n              \"labelClassName\": \"labelClassName-a3e712484fae\"\n            },\n            {\n              \"type\": \"input-text\",\n              \"label\": \"接口数据字段 PATH\",\n              \"name\": \"result\",\n              \"id\": \"u:8c082acf7db2\",\n              \"value\": \"[\\\"result\\\"][\\\"records\\\"]\",\n              \"description\": \"\"\n            },\n            {\n              \"type\": \"input-text\",\n              \"label\": \"service方法名\",\n              \"name\": \"serviceName\",\n              \"id\": \"u:cfbbdd07366b\",\n              \"value\": \"getTableList\",\n              \"description\": \"\"\n            }\n          ],\n          \"id\": \"u:382f8cdf59a6\",\n          \"collapsed\": true,\n          \"className\": \"\",\n          \"headingClassName\": \"\",\n          \"bodyClassName\": \"p-r p-l p-b\"\n        },\n        {\n          \"type\": \"fieldset\",\n          \"title\": \"新增/编辑弹框\",\n          \"collapsable\": true,\n          \"body\": [\n            {\n              \"type\": \"switch\",\n              \"label\": \"是否包含弹框\",\n              \"option\": \"\",\n              \"name\": \"includeModifyModal\",\n              \"falseValue\": false,\n              \"trueValue\": true,\n              \"id\": \"u:03957070af9e\",\n              \"value\": false\n            },\n            {\n              \"type\": \"combo\",\n              \"label\": \"表单项\",\n              \"name\": \"modifyModal.formItems\",\n              \"multiple\": true,\n              \"addable\": true,\n              \"removable\": true,\n              \"removableMode\": \"icon\",\n              \"strictMode\": false,\n              \"addBtn\": {\n                \"label\": \"新增\",\n                \"icon\": \"fa fa-plus\",\n                \"level\": \"primary\",\n                \"size\": \"sm\",\n                \"id\": \"u:86cc27b6a663\"\n              },\n              \"items\": [\n                {\n                  \"type\": \"input-text\",\n                  \"name\": \"key\",\n                  \"id\": \"u:62cc1cf36c73\",\n                  \"label\": \"字段名（key）\"\n                },\n                {\n                  \"type\": \"select\",\n                  \"name\": \"type\",\n                  \"options\": [\n                    {\n                      \"label\": \"string\",\n                      \"value\": \"string\"\n                    },\n                    {\n                      \"label\": \"number\",\n                      \"value\": \"number\"\n                    },\n                    {\n                      \"label\": \"boolean\",\n                      \"value\": \"boolean\"\n                    },\n                    {\n                      \"label\": \"Dayjs\",\n                      \"value\": \"Dayjs\"\n                    },\n                    {\n                      \"label\": \"string[]\",\n                      \"value\": \"string[]\"\n                    },\n                    {\n                      \"label\": \"number[]\",\n                      \"value\": \"number[]\"\n                    },\n                    {\n                      \"label\": \"boolean[]\",\n                      \"value\": \"boolean[]\"\n                    },\n                    {\n                      \"label\": \"[Dayjs,Dayjs]\",\n                      \"value\": \"[Dayjs,Dayjs]\"\n                    }\n                  ],\n                  \"id\": \"u:b165c75e5e1a\",\n                  \"multiple\": false,\n                  \"label\": \"字段类型\",\n                  \"value\": \"\"\n                },\n                {\n                  \"type\": \"switch\",\n                  \"label\": \"字段可选\",\n                  \"option\": \"\",\n                  \"name\": \"optional\",\n                  \"falseValue\": false,\n                  \"trueValue\": true,\n                  \"id\": \"u:68fc4c85fb03\",\n                  \"value\": false,\n                  \"description\": \"字段名字后加?\"\n                },\n                {\n                  \"type\": \"select\",\n                  \"name\": \"defaultValue\",\n                  \"options\": [\n                    {\n                      \"label\": \"\\\"\\\"\",\n                      \"value\": \"\\\"\\\"\"\n                    },\n                    {\n                      \"label\": \"false\",\n                      \"value\": \"false\"\n                    },\n                    {\n                      \"label\": \"true\",\n                      \"value\": \"true\"\n                    },\n                    {\n                      \"label\": \"0\",\n                      \"value\": \"0\"\n                    },\n                    {\n                      \"label\": \"undefined\",\n                      \"value\": \"undefined\"\n                    },\n                    {\n                      \"label\": \"[]\",\n                      \"value\": \"[]\"\n                    }\n                  ],\n                  \"id\": \"u:379ea92fb3c6\",\n                  \"multiple\": false,\n                  \"label\": \"默认值\",\n                  \"value\": \"\"\n                },\n                {\n                  \"type\": \"select\",\n                  \"name\": \"component\",\n                  \"options\": [\n                    {\n                      \"label\": \"input\",\n                      \"value\": \"input\"\n                    },\n                    {\n                      \"label\": \"input-password\",\n                      \"value\": \"input-password\"\n                    },\n                    {\n                      \"label\": \"input-number\",\n                      \"value\": \"input-number\"\n                    },\n                    {\n                      \"label\": \"textarea\",\n                      \"value\": \"textarea\"\n                    },\n                    {\n                      \"label\": \"select\",\n                      \"value\": \"select\"\n                    },\n                    {\n                      \"label\": \"radio-group\",\n                      \"value\": \"radio-group\"\n                    },\n                    {\n                      \"label\": \"checkbox-group\",\n                      \"value\": \"checkbox-group\"\n                    },\n                    {\n                      \"label\": \"switch\",\n                      \"value\": \"switch\"\n                    },\n                    {\n                      \"label\": \"date-picker\",\n                      \"value\": \"date-picker\"\n                    },\n                    {\n                      \"label\": \"time-ticker\",\n                      \"value\": \"time-picker\"\n                    },\n                    {\n                      \"label\": \"range-picker\",\n                      \"value\": \"range-picker\"\n                    },\n                    {\n                      \"label\": \"transfer\",\n                      \"value\": \"transfer\"\n                    }\n                  ],\n                  \"id\": \"u:7932ea3b05da\",\n                  \"multiple\": false,\n                  \"label\": \"组件\",\n                  \"value\": \"\"\n                },\n                {\n                  \"type\": \"input-text\",\n                  \"name\": \"label\",\n                  \"id\": \"u:5bb237f20098\",\n                  \"label\": \"label\"\n                },\n                {\n                  \"type\": \"input-text\",\n                  \"name\": \"placeholder\",\n                  \"id\": \"u:580898257491\",\n                  \"label\": \"placeholder\"\n                },\n                {\n                  \"type\": \"switch\",\n                  \"label\": \"required\",\n                  \"option\": \"\",\n                  \"name\": \"required\",\n                  \"falseValue\": false,\n                  \"trueValue\": true,\n                  \"id\": \"u:559dbdbb01da\",\n                  \"value\": false,\n                  \"description\": \"验证规则加required\"\n                },\n                {\n                  \"type\": \"input-text\",\n                  \"name\": \"message\",\n                  \"id\": \"u:55013279d659\",\n                  \"label\": \"校验失败 message\",\n                  \"value\": \"不能为空\"\n                },\n                {\n                  \"type\": \"switch\",\n                  \"label\": \"更多组件配置\",\n                  \"option\": \"\",\n                  \"name\": \"showMore\",\n                  \"falseValue\": false,\n                  \"trueValue\": true,\n                  \"id\": \"u:67e0cb5b7496\",\n                  \"value\": false,\n                  \"description\": \"\"\n                },\n                {\n                  \"type\": \"switch\",\n                  \"label\": \"labelInValue\",\n                  \"option\": \"\",\n                  \"name\": \"labelInValue\",\n                  \"falseValue\": false,\n                  \"trueValue\": true,\n                  \"id\": \"u:7fd6f1b233d9\",\n                  \"value\": false,\n                  \"description\": \"是否把每个选项的 label 包装到 value 中\",\n                  \"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'select'}\"\n                },\n                {\n                  \"type\": \"select\",\n                  \"name\": \"mode\",\n                  \"options\": [\n                    {\n                      \"label\": \"multiple\",\n                      \"value\": \"multiple\"\n                    },\n                    {\n                      \"label\": \"tags\",\n                      \"value\": \"tags\"\n                    }\n                  ],\n                  \"multiple\": false,\n                  \"label\": \"mode\",\n                  \"value\": \"\",\n                  \"description\": \"设置 Select 的模式为多选或标签\",\n                  \"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'select'}\"\n                },\n                {\n                  \"type\": \"input-text\",\n                  \"name\": \"optionFilterProp\",\n                  \"label\": \"optionFilterProp\",\n                  \"description\": \"搜索时过滤对应的 option 属性\",\n                  \"value\": \"label\",\n                  \"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'select'}\"\n                },\n                {\n                  \"type\": \"switch\",\n                  \"label\": \"showSearch\",\n                  \"option\": \"\",\n                  \"name\": \"showSearch\",\n                  \"falseValue\": false,\n                  \"trueValue\": true,\n                  \"value\": false,\n                  \"description\": \"使单选模式可搜索\",\n                  \"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'select'}\"\n                },\n                {\n                  \"type\": \"switch\",\n                  \"label\": \"hideArrow\",\n                  \"option\": \"\",\n                  \"name\": \"hideArrow\",\n                  \"falseValue\": false,\n                  \"trueValue\": true,\n                  \"value\": false,\n                  \"description\": \"是否隐藏下拉小箭头\",\n                  \"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'select'}\"\n                },\n                {\n                  \"type\": \"input-text\",\n                  \"name\": \"maxlength\",\n                  \"label\": \"maxlength\",\n                  \"description\": \"最大长度\",\n                  \"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'input' && modifyModal.formItems[index].component !== 'input-password' && modifyModal.formItems[index].component !== 'textarea')}\"\n                },\n                {\n                  \"type\": \"switch\",\n                  \"label\": \"showCount\",\n                  \"option\": \"\",\n                  \"name\": \"showCount\",\n                  \"falseValue\": false,\n                  \"trueValue\": true,\n                  \"value\": false,\n                  \"description\": \"是否展示字数\",\n                  \"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'input' && modifyModal.formItems[index].component !== 'input-password' && modifyModal.formItems[index].component !== 'textarea')}\"\n                },\n                {\n                  \"type\": \"input-text\",\n                  \"name\": \"max\",\n                  \"label\": \"max\",\n                  \"description\": \"最大值\",\n                  \"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'input-number'}\"\n                },\n                {\n                  \"type\": \"input-text\",\n                  \"name\": \"min\",\n                  \"label\": \"min\",\n                  \"description\": \"最小值\",\n                  \"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'input-number'}\"\n                },\n                {\n                  \"type\": \"input-text\",\n                  \"name\": \"step\",\n                  \"label\": \"step\",\n                  \"description\": \"每次改变步数，可以为小数\",\n                  \"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'input-number'}\"\n                },\n                {\n                  \"type\": \"input-text\",\n                  \"name\": \"checkedChildren\",\n                  \"label\": \"checkedChildren\",\n                  \"description\": \"选中时的内容\",\n                  \"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'switch'}\"\n                },\n                {\n                  \"type\": \"input-text\",\n                  \"name\": \"unCheckedChildren\",\n                  \"label\": \"unCheckedChildren\",\n                  \"description\": \"非选中时的内容\",\n                  \"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'switch'}\"\n                },\n                {\n                  \"type\": \"input-text\",\n                  \"name\": \"checkedValue\",\n                  \"label\": \"checkedValue\",\n                  \"description\": \"选中时的值\",\n                  \"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'switch'}\"\n                },\n                {\n                  \"type\": \"input-text\",\n                  \"name\": \"unCheckedValue\",\n                  \"label\": \"unCheckedValue\",\n                  \"description\": \"非选中时的值\",\n                  \"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'switch'}\"\n                },\n                {\n                  \"type\": \"select\",\n                  \"name\": \"picker\",\n                  \"options\": [\n                    {\n                      \"label\": \"date\",\n                      \"value\": \"date\"\n                    },\n                    {\n                      \"label\": \"week\",\n                      \"value\": \"week\"\n                    },\n                    {\n                      \"label\": \"month\",\n                      \"value\": \"month\"\n                    },\n                    {\n                      \"label\": \"quarter\",\n                      \"value\": \"quarter\"\n                    },\n                    {\n                      \"label\": \"year\",\n                      \"value\": \"year\"\n                    }\n                  ],\n                  \"multiple\": false,\n                  \"label\": \"picker\",\n                  \"description\": \"设置选择器类型\",\n                  \"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'date-picker' && modifyModal.formItems[index].component !== 'range-picker')}\"\n                },\n                {\n                  \"type\": \"switch\",\n                  \"label\": \"showTime\",\n                  \"name\": \"showTime\",\n                  \"falseValue\": false,\n                  \"trueValue\": true,\n                  \"value\": false,\n                  \"description\": \"增加时间选择功能\",\n                  \"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'date-picker' && modifyModal.formItems[index].component !== 'range-picker' || modifyModal.formItems[index].picker !== 'date')}\"\n                },\n                {\n                  \"type\": \"switch\",\n                  \"label\": \"showNow\",\n                  \"name\": \"showNow\",\n                  \"falseValue\": false,\n                  \"trueValue\": true,\n                  \"value\": false,\n                  \"description\": \"当设定了 showTime 的时候，面板是否显示“此刻”按钮\",\n                  \"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'date-picker' && modifyModal.formItems[index].component !== 'range-picker' || modifyModal.formItems[index].picker !== 'date')}\"\n                },\n                {\n                  \"type\": \"switch\",\n                  \"label\": \"showToday\",\n                  \"name\": \"showToday\",\n                  \"falseValue\": false,\n                  \"trueValue\": true,\n                  \"value\": false,\n                  \"description\": \"是否展示“今天”按钮\",\n                  \"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'date-picker' && modifyModal.formItems[index].component !== 'range-picker' || modifyModal.formItems[index].picker !== 'date')}\"\n                }\n              ],\n              \"syncFields\": [],\n              \"tabsMode\": true,\n              \"draggable\": true,\n              \"draggableTip\": \"可拖动排序\",\n              \"tabsStyle\": \"line\",\n              \"tabsLabelTpl\": \"表单项${index+1}\",\n              \"multiLine\": true,\n              \"noBorder\": false,\n              \"hiddenOn\": \"${!includeModifyModal}\"\n            }\n          ],\n          \"bodyClassName\": \"p\",\n          \"collapsed\": true\n        }\n      ],\n      \"submitText\": \"\"\n    }\n  ],\n  \"pullRefresh\": {\n    \"disabled\": true\n  },\n  \"regions\": [\"body\"],\n  \"style\": {\n    \"boxShadow\": \" 0px 0px 0px 0px transparent\"\n  },\n  \"asideResizor\": false\n}\n"
  },
  {
    "path": "materials/snippets/动态表单 demo/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/动态表单 demo/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/动态表单 demo/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: (lowcodeContext) => {},\n  onSelect: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    await main.bootstrap();\n  },\n};\n"
  },
  {
    "path": "materials/snippets/动态表单 demo/script/src/context.ts",
    "content": "import { CompileContext } from 'lowcode-context';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n} = {\n  lowcodeContext: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/动态表单 demo/script/src/controller.ts",
    "content": "import * as vscode from 'vscode';\nimport { CompileContext } from 'lowcode-context';\nimport { IMessage } from '@share/WebView/type';\n\ntype RunDynamicFormScript = (\n  message: IMessage<{\n    method: string;\n    params: string;\n    model: object;\n  }>,\n  lowcodeContext: {\n    webview: vscode.Webview;\n  } & CompileContext,\n) => Promise<{\n  /** 立即更新 model */\n  updateModelImmediately: boolean;\n  /** 仅更新参数 */\n  onlyUpdateParams: boolean;\n  params?: string;\n  model: object;\n}>;\n\nexport const runDynamicFormScript: RunDynamicFormScript = async (\n  message,\n  lowcodeContext,\n) => {\n  return Promise.resolve({\n    model: message.data.model,\n    updateModelImmediately: false,\n    onlyUpdateParams: true,\n    params: `执行了方法：${message.data.method}`,\n  });\n};\n"
  },
  {
    "path": "materials/snippets/动态表单 demo/script/src/main.ts",
    "content": "import { window } from 'vscode';\nimport { showWebView } from '@share/WebView';\nimport { routes } from './routes';\nimport { context } from './context';\n\nexport async function bootstrap() {\n  const { lowcodeContext } = context;\n  showWebView({\n    key: 'main',\n    title: '动态表单',\n    viewColumn: 3,\n    task: {\n      task: 'route',\n      data: {\n        path: '/dynamicForm',\n        materialPath: lowcodeContext?.materialPath,\n      },\n    },\n    lowcodeContext: {\n      ...lowcodeContext!,\n    },\n    htmlForWebview: getHtmlForWebview(false),\n    routes,\n  });\n}\n\nconst getHtmlForWebview = (dev = false) => {\n  if (dev) {\n    return `\n\t\t\t\t<!doctype html>\n\t\t\t\t<html lang=\"en\">\n\t\t\t\t\t<head>\n\t\t\t\t\t\t<script type=\"module\">import { injectIntoGlobalHook } from \"http://127.0.0.1:5173/@react-refresh\";\n\t\t\t\t\t\tinjectIntoGlobalHook(window);\n\t\t\t\t\t\twindow.$RefreshReg$ = () => {};\n\t\t\t\t\t\twindow.$RefreshSig$ = () => (type) => type;</script>\n\n\t\t\t\t\t\t<script type=\"module\" src=\"http://127.0.0.1:5173/@vite/client\"></script>\n\t\t\t\t\t\t<script>\n\t\t\t\t\t\t\twindow.vscode = acquireVsCodeApi();\n\t\t\t\t\t\t</script>\n\t\t\t\t\t\t<meta charset=\"UTF-8\" />\n\t\t\t\t\t\t<link rel=\"icon\" type=\"image/svg+xml\" href=\"http://127.0.0.1:5173/vite.svg\" />\n\t\t\t\t\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n\t\t\t\t\t</head>\n\t\t\t\t\t<body>\n\t\t\t\t\t\t<div id=\"root\"></div>\n\t\t\t\t\t\t<script type=\"module\" src=\"http://127.0.0.1:5173/src/main.tsx\"></script>\n\t\t\t\t\t</body>\n\t\t\t\t</html>\n\t\t`;\n  }\n  return `\n\t\t\t<!DOCTYPE html>\n\t\t\t<html>\n\t\t\t<head>\n\t\t\t\t<meta charset=\"utf-8\" />\n\t\t\t\t<meta\n\t\t\t\t\tname=\"viewport\"\n\t\t\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no\"\n\t\t\t\t/>\n\t\t\t\t<script>\n\t\t\t\t   window.vscode = acquireVsCodeApi();\n        </script>\n\t\t\t\t<script type=\"module\" crossorigin src=\"http://lowcode-utools.oss-cn-beijing.aliyuncs.com/vscode.index.js\"></script>\n\t\t\t\t<link rel=\"stylesheet\" crossorigin href=\"http://lowcode-utools.oss-cn-beijing.aliyuncs.com/vscode.index.css\">\n\t\t\t</head>\n\t\t\t<body>\n\t\t\t\t<div id=\"root\"></div>\n\t\t\t</body>\n\t\t</html>\n`;\n};\n"
  },
  {
    "path": "materials/snippets/动态表单 demo/script/src/routes.ts",
    "content": "import * as controller from './controller';\n\nexport const routes: Record<string, any> = {\n  runDynamicFormScript: controller.runDynamicFormScript,\n};\n"
  },
  {
    "path": "materials/snippets/动态表单 demo/src/template.ejs",
    "content": "代码片段"
  },
  {
    "path": "materials/snippets/当前目录翻译成英文/config/model.json",
    "content": "{\n  \"name\": \"lowcode\"\n}"
  },
  {
    "path": "materials/snippets/当前目录翻译成英文/config/preview.json",
    "content": "{\n\t\"title\": \"\",\n\t\"description\": \"\",\n\t\"img\": [\n\t\t\"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n\t],\n\t\"category\": [],\n\t\"notShowInCommand\": true,\n\t\"notShowInSnippetsList\": true,\n\t\"notShowInintellisense\": true,\n\t\"showInRunSnippetScript\": false,\n\t\"showInRunSnippetScriptOnExplorer\": true,\n\t\"schema\": \"amis\",\n\t\"scripts\": []\n}"
  },
  {
    "path": "materials/snippets/当前目录翻译成英文/config/schema.json",
    "content": "{\n  \"formSchema\": {\n    \"schema\": {\n      \"type\": \"page\",\n      \"body\": [\n        {\n          \"type\": \"form\",\n          \"title\": \"\",\n          \"body\": [\n            {\n              \"type\": \"input-text\",\n              \"name\": \"name\",\n              \"label\": \"测试表单\",\n              \"id\": \"u:4886baa626cf\",\n              \"value\": \"\"\n            }\n          ],\n          \"id\": \"u:67967afb0e69\",\n          \"submitText\": \"\"\n        }\n      ],\n      \"id\": \"u:d87dbf6bf8df\",\n      \"asideResizor\": false,\n      \"style\": {\n        \"boxShadow\": \" 0px 0px 0px 0px transparent\"\n      },\n      \"pullRefresh\": {\n        \"disabled\": true\n      },\n      \"regions\": [\n        \"body\"\n      ]\n    }\n  }\n}"
  },
  {
    "path": "materials/snippets/当前目录翻译成英文/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/当前目录翻译成英文/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/当前目录翻译成英文/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: (lowcodeContext) => {},\n  onSelect: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    await main.bootstrap();\n  },\n};\n"
  },
  {
    "path": "materials/snippets/当前目录翻译成英文/script/src/context.ts",
    "content": "import { CompileContext } from 'lowcode-context';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n} = {\n  lowcodeContext: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/当前目录翻译成英文/script/src/main.ts",
    "content": "import * as path from 'path';\nimport * as vscode from 'vscode';\nimport * as fs from 'fs-extra';\nimport { context } from './context';\n\nexport async function bootstrap() {\n  const { lowcodeContext } = context;\n  const explorerSelectedPath = path\n    .join(lowcodeContext?.explorerSelectedPath || '')\n    .replace(/\\\\/g, '/');\n  const explorerSelectedPathArr = explorerSelectedPath.split('/');\n  const name = explorerSelectedPathArr.pop();\n  vscode.window.withProgress(\n    {\n      location: vscode.ProgressLocation.Notification,\n    },\n    async (progress) => {\n      progress.report({\n        message: `loading`,\n      });\n\n      let content = await context.lowcodeContext!.createChatCompletion({\n        messages: [\n          {\n            role: 'system',\n            content: `你是一个翻译家，你的目标是把中文翻译成英文单词，请翻译时使用驼峰格式，小写字母开头，不要带翻译腔，而是要翻译得自然、流畅和地道，使用优美和高雅的表达方式。请翻译下面用户输入的内容`,\n          },\n          {\n            role: 'user',\n            content: name || '',\n          },\n        ],\n      });\n      content = content.charAt(0).toLowerCase() + content.slice(1);\n      fs.renameSync(\n        path.join(lowcodeContext?.explorerSelectedPath || ''),\n        path.join(explorerSelectedPathArr.join('/'), content),\n      );\n    },\n  );\n}\n"
  },
  {
    "path": "materials/snippets/快速创建区块/config/model.json",
    "content": "{\n  \"name\": \"lowcode\"\n}"
  },
  {
    "path": "materials/snippets/快速创建区块/config/preview.json",
    "content": "{\n\t\"title\": \"\",\n\t\"description\": \"\",\n\t\"img\": [\n\t\t\"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n\t],\n\t\"category\": [],\n\t\"notShowInCommand\": true,\n\t\"notShowInSnippetsList\": true,\n\t\"notShowInintellisense\": true,\n\t\"showInRunSnippetScript\": false,\n\t\"showInRunSnippetScriptOnExplorer\": true,\n\t\"schema\": \"amis\",\n\t\"scripts\": []\n}"
  },
  {
    "path": "materials/snippets/快速创建区块/config/schema.json",
    "content": "{\n  \"formSchema\": {\n    \"schema\": {\n      \"type\": \"page\",\n      \"body\": [\n        {\n          \"type\": \"form\",\n          \"title\": \"\",\n          \"body\": [\n            {\n              \"type\": \"input-text\",\n              \"name\": \"name\",\n              \"label\": \"测试表单\",\n              \"id\": \"u:4886baa626cf\",\n              \"value\": \"\"\n            }\n          ],\n          \"id\": \"u:67967afb0e69\",\n          \"submitText\": \"\"\n        }\n      ],\n      \"id\": \"u:d87dbf6bf8df\",\n      \"asideResizor\": false,\n      \"style\": {\n        \"boxShadow\": \" 0px 0px 0px 0px transparent\"\n      },\n      \"pullRefresh\": {\n        \"disabled\": true\n      },\n      \"regions\": [\n        \"body\"\n      ]\n    }\n  }\n}"
  },
  {
    "path": "materials/snippets/快速创建区块/config/viewPrompt.ejs",
    "content": ""
  },
  {
    "path": "materials/snippets/快速创建区块/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/快速创建区块/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/快速创建区块/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: (lowcodeContext) => {},\n  onSelect: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    await main.bootstrap();\n  },\n};\n"
  },
  {
    "path": "materials/snippets/快速创建区块/script/src/context.ts",
    "content": "import { CompileContext } from 'lowcode-context';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n} = {\n  lowcodeContext: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/快速创建区块/script/src/main.ts",
    "content": "import * as path from 'path';\nimport { window } from 'vscode';\nimport * as fs from 'fs-extra';\nimport { renderEjsTemplates } from '@share/utils/ejs';\nimport { context } from './context';\n\nexport async function bootstrap() {\n  const { lowcodeContext } = context;\n  const result = await window.showQuickPick(\n    [\n      'uniapp/vue3-mvp',\n      'uniapp/vue3-mvp emit',\n      'uniapp/vue3-mvp props',\n      'uniapp/vue3-mvp props emit',\n      'lowcode/代码片段',\n      'uTools 自动化脚本',\n      'uTools 动态表单',\n      'uTools askChatGPT',\n    ].map((s) => s),\n    { placeHolder: '请选择模板' },\n  );\n  if (!result) {\n    return;\n  }\n  const tempWorkPath = path.join(\n    lowcodeContext?.env.rootPath || '',\n    '.lowcode',\n  );\n  fs.copySync(path.join(lowcodeContext?.materialPath || ''), tempWorkPath);\n  await renderEjsTemplates(\n    {\n      createBlockPath: path\n        .join(lowcodeContext?.explorerSelectedPath || '')\n        .replace(/\\\\/g, '/'),\n    },\n    path.join(tempWorkPath, 'src'),\n  );\n  fs.copySync(\n    path.join(tempWorkPath, 'src', result),\n    path.join(lowcodeContext?.explorerSelectedPath || ''),\n  );\n  fs.removeSync(tempWorkPath);\n}\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/lowcode/代码片段/config/commandPrompt.ejs.ejs",
    "content": "Ask ChatGPT With Template 内容 \n可用变量：\nrawSelectedText\nrawClipboardText"
  },
  {
    "path": "materials/snippets/快速创建区块/src/lowcode/代码片段/config/model.json",
    "content": "{\n  \"name\": \"lowcode\"\n}"
  },
  {
    "path": "materials/snippets/快速创建区块/src/lowcode/代码片段/config/preview.json",
    "content": "{\n\t\"title\": \"\",\n\t\"description\": \"\",\n\t\"img\": [\n\t\t\"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n\t],\n\t\"category\": [],\n\t\"notShowInCommand\": true,\n\t\"notShowInSnippetsList\": true,\n\t\"notShowInintellisense\": true,\n\t\"showInRunSnippetScript\": true,\n\t\"showInRunSnippetScriptOnExplorer\": false,\n\t\"runActivate\": false,\n\t\"schema\": \"amis\",\n\t\"scripts\": []\n}"
  },
  {
    "path": "materials/snippets/快速创建区块/src/lowcode/代码片段/config/schema.json",
    "content": "{\n  \"formSchema\": {\n    \"schema\": {\n      \"type\": \"page\",\n      \"body\": [\n        {\n          \"type\": \"form\",\n          \"title\": \"\",\n          \"body\": [\n            {\n              \"type\": \"input-text\",\n              \"name\": \"name\",\n              \"label\": \"测试表单\",\n              \"id\": \"u:4886baa626cf\",\n              \"value\": \"\"\n            }\n          ],\n          \"id\": \"u:67967afb0e69\",\n          \"submitText\": \"\"\n        }\n      ],\n      \"id\": \"u:d87dbf6bf8df\",\n      \"asideResizor\": false,\n      \"style\": {\n        \"boxShadow\": \" 0px 0px 0px 0px transparent\"\n      },\n      \"pullRefresh\": {\n        \"disabled\": true\n      },\n      \"regions\": [\n        \"body\"\n      ]\n    }\n  }\n}"
  },
  {
    "path": "materials/snippets/快速创建区块/src/lowcode/代码片段/script/index.js.ejs",
    "content": "require('ts-node').register({\n  transpileOnly: true,\n  typeCheck: false,\n  emit: false,\n  compilerHost: false, // 和 emit 一起设置为 true，会在 .ts-node 文件夹输出编译后的代码\n  cwd: __dirname, // 要输出编译后代码必须配置，否则会报错 EROFS: read-only file system, mkdir '/.ts-node'。不输出也要配置不然会出现各种奇奇怪怪的报错\n});\n// 清除缓存，保证每次修改代码后实时生效，否则要重新打开 vscode\nconst { clearCache } = require('@share/clearCache.ts');\n\nclearCache(__dirname); // 调试的时候才打开，不然会很慢\nconst main = require('./src/main.ts');\nconst { context } = require('./src/context.ts');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: (lowcodeContext) => {},\n  onSelect: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    await main.bootstrap();\n  },\n};\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/lowcode/代码片段/script/src/context.ts.ejs",
    "content": "import { CompileContext } from 'lowcode-context';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n} = {\n  lowcodeContext: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/lowcode/代码片段/script/src/main.ts.ejs",
    "content": "export function bootstrap() {}\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/lowcode/代码片段/src/template.ejs.ejs",
    "content": "代码片段"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uTools askChatGPT/script/index.ts.ejs",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uTools askChatGPT/script/src/main.ts.ejs",
    "content": "import { LLMMessage } from '@share/uTools/webviewBaseController';\nimport { askChatGPT as askOpenai } from '@share/utils/uTools';\n\nexport const bootstrap = async (scriptFile?: string) => {\n  const requestPrompt = '你好';\n  const content = await askOpenai({\n    messages: [{ role: 'user', content: requestPrompt }],\n    handleChunk: () => {},\n  });\n  utools.outPlugin();\n  utools.hideMainWindowPasteText(content.content);\n};\n\n// 给页面调用的\nexport const askChatGPT = (data: {\n  messages: LLMMessage;\n  handleChunk: (chunck: string) => void;\n}) => askOpenai({ ...data });\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uTools 动态表单/config/config.json",
    "content": "{\n\t\"scripts\": [\n\t\t{\n\t\t\t\"method\": \"initFiltersFromImage\",\n\t\t\t\"remark\": \"使用 OCR 识别查询条件截图内容\"\n\t\t},\n\t\t{\n\t\t\t\"method\": \"initFiltersFromText\",\n\t\t\t\"remark\": \"使用文本初始化查询条件\"\n\t\t},\n\t\t{\n\t\t\t\"method\": \"initColumnsFromText\",\n\t\t\t\"remark\": \"使用文本初始化表格\"\n\t\t},\n\t\t{\n\t\t\t\"method\": \"openChatGPT\",\n\t\t\t\"remark\": \"使用 ChatGPT 翻译模版数据里的指定中文字段\"\n\t\t},\n\t\t{\n\t\t\t\"method\": \"generateCode\",\n\t\t\t\"remark\": \"生成代码\"\n\t\t}\n\t]\n}"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uTools 动态表单/config/model.json",
    "content": "{\n  \"filters\": [],\n  \"columns\": [],\n  \"pagination\": {\n    \"show\": true,\n    \"page\": \"page\",\n    \"size\": \"size\",\n    \"total\": \"result.total\"\n  },\n  \"includeModifyModal\": false,\n  \"fetchName\": \"fetchTableList\",\n  \"result\": \"[\\\"result\\\"][\\\"records\\\"]\",\n  \"serviceName\": \"getTableList\"\n}\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uTools 动态表单/config/schema.json",
    "content": "{\n\t\"type\": \"page\",\n\t\"body\": [\n\t\t{\n\t\t\t\"type\": \"form\",\n\t\t\t\"title\": \"\",\n\t\t\t\"body\": [\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"combo\",\n\t\t\t\t\t\"label\": \"查询条件\",\n\t\t\t\t\t\"name\": \"filters\",\n\t\t\t\t\t\"multiple\": true,\n\t\t\t\t\t\"addable\": true,\n\t\t\t\t\t\"removable\": true,\n\t\t\t\t\t\"removableMode\": \"icon\",\n\t\t\t\t\t\"addBtn\": {\n\t\t\t\t\t\t\"label\": \"新增\",\n\t\t\t\t\t\t\"icon\": \"fa fa-plus\",\n\t\t\t\t\t\t\"level\": \"primary\",\n\t\t\t\t\t\t\"size\": \"sm\",\n\t\t\t\t\t\t\"id\": \"u:47ecb9e15ff1\"\n\t\t\t\t\t},\n\t\t\t\t\t\"items\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"name\": \"key\",\n\t\t\t\t\t\t\t\"placeholder\": \"字段名\",\n\t\t\t\t\t\t\t\"id\": \"u:25b0c7b5e5a0\",\n\t\t\t\t\t\t\t\"label\": \"字段名（key）\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"label\": \"label\",\n\t\t\t\t\t\t\t\"name\": \"label\",\n\t\t\t\t\t\t\t\"id\": \"u:6496cac4f4b8\",\n\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\"name\": \"component\",\n\t\t\t\t\t\t\t\"placeholder\": \"选项\",\n\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"label\": \"input\",\n\t\t\t\t\t\t\t\t\t\"value\": \"input\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"label\": \"select\",\n\t\t\t\t\t\t\t\t\t\"value\": \"select\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"id\": \"u:995915eabcca\",\n\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\"label\": \"组件\",\n\t\t\t\t\t\t\t\"value\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"label\": \"placeholder\",\n\t\t\t\t\t\t\t\"name\": \"placeholder\",\n\t\t\t\t\t\t\t\"id\": \"u:d7f1a8a39449\",\n\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\t\"id\": \"u:186f183e9320\",\n\t\t\t\t\t\"strictMode\": false,\n\t\t\t\t\t\"syncFields\": [],\n\t\t\t\t\t\"tabsMode\": true,\n\t\t\t\t\t\"draggable\": true,\n\t\t\t\t\t\"draggableTip\": \"可拖动排序\",\n\t\t\t\t\t\"tabsStyle\": \"line\",\n\t\t\t\t\t\"tabsLabelTpl\": \"表单项${index+1}\",\n\t\t\t\t\t\"multiLine\": true,\n\t\t\t\t\t\"noBorder\": false\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"combo\",\n\t\t\t\t\t\"label\": \"表格\",\n\t\t\t\t\t\"name\": \"columns\",\n\t\t\t\t\t\"multiple\": true,\n\t\t\t\t\t\"addable\": true,\n\t\t\t\t\t\"removable\": true,\n\t\t\t\t\t\"removableMode\": \"button\",\n\t\t\t\t\t\"addBtn\": {\n\t\t\t\t\t\t\"label\": \"新增\",\n\t\t\t\t\t\t\"icon\": \"fa fa-plus\",\n\t\t\t\t\t\t\"level\": \"primary\",\n\t\t\t\t\t\t\"size\": \"sm\",\n\t\t\t\t\t\t\"id\": \"u:1e8070edc3d3\"\n\t\t\t\t\t},\n\t\t\t\t\t\"items\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"name\": \"title\",\n\t\t\t\t\t\t\t\"id\": \"u:152dd82b82f9\",\n\t\t\t\t\t\t\t\"label\": \"title\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"label\": \"dataIndex\",\n\t\t\t\t\t\t\t\"name\": \"dataIndex\",\n\t\t\t\t\t\t\t\"id\": \"u:ecc7298e0550\",\n\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"label\": \"key\",\n\t\t\t\t\t\t\t\"name\": \"key\",\n\t\t\t\t\t\t\t\"id\": \"u:fbaa95c3f15d\",\n\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"label\": \"width\",\n\t\t\t\t\t\t\t\"name\": \"width\",\n\t\t\t\t\t\t\t\"id\": \"u:b143127e097b\",\n\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\"label\": \"自定义插槽\",\n\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\"name\": \"slot\",\n\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\"id\": \"u:ee1ce1faee0b\",\n\t\t\t\t\t\t\t\"value\": false\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\t\"id\": \"u:9b9fb0cf38f9\",\n\t\t\t\t\t\"strictMode\": true,\n\t\t\t\t\t\"syncFields\": [],\n\t\t\t\t\t\"tabsMode\": true,\n\t\t\t\t\t\"draggable\": true,\n\t\t\t\t\t\"draggableTip\": \"可拖动排序\",\n\t\t\t\t\t\"tabsStyle\": \"line\",\n\t\t\t\t\t\"deleteBtn\": {\n\t\t\t\t\t\t\"label\": \"删除\",\n\t\t\t\t\t\t\"level\": \"default\"\n\t\t\t\t\t},\n\t\t\t\t\t\"tabsLabelTpl\": \"列${index+1}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"fieldset\",\n\t\t\t\t\t\"title\": \"分页参数\",\n\t\t\t\t\t\"collapsable\": true,\n\t\t\t\t\t\"body\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\"label\": \"是否分页\",\n\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\"name\": \"pagination.show\",\n\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\"id\": \"u:6c70041d5143\",\n\t\t\t\t\t\t\t\"value\": true,\n\t\t\t\t\t\t\t\"className\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"label\": \"查询接口页数参数字段名\",\n\t\t\t\t\t\t\t\"name\": \"pagination.page\",\n\t\t\t\t\t\t\t\"id\": \"u:cbbf6853cf64\",\n\t\t\t\t\t\t\t\"value\": \"page\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"label\": \"查询接口每页数据行数参数字段名\",\n\t\t\t\t\t\t\t\"name\": \"pagination.size\",\n\t\t\t\t\t\t\t\"id\": \"u:a8fae66fa927\",\n\t\t\t\t\t\t\t\"value\": \"size\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"label\": \"接口返回总数据量字段 PATH\",\n\t\t\t\t\t\t\t\"name\": \"pagination.total\",\n\t\t\t\t\t\t\t\"id\": \"u:e1cd979c7ee8\",\n\t\t\t\t\t\t\t\"value\": \"result.total\",\n\t\t\t\t\t\t\t\"themeCss\": {\n\t\t\t\t\t\t\t\t\"inputControlClassName\": {\n\t\t\t\t\t\t\t\t\t\"padding-and-margin:default\": {\n\t\t\t\t\t\t\t\t\t\t\"marginBottom\": \"\",\n\t\t\t\t\t\t\t\t\t\t\"marginTop\": \"\",\n\t\t\t\t\t\t\t\t\t\t\"marginRight\": \"\",\n\t\t\t\t\t\t\t\t\t\t\"marginLeft\": \"\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\t\"id\": \"u:0f1bd8fc2f2b\",\n\t\t\t\t\t\"collapsed\": true,\n\t\t\t\t\t\"headingClassName\": \"\",\n\t\t\t\t\t\"bodyClassName\": \"p\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"fieldset\",\n\t\t\t\t\t\"title\": \"请求方法\",\n\t\t\t\t\t\"collapsable\": true,\n\t\t\t\t\t\"body\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"label\": \"请求名称\",\n\t\t\t\t\t\t\t\"name\": \"fetchName\",\n\t\t\t\t\t\t\t\"id\": \"u:a3e712484fae\",\n\t\t\t\t\t\t\t\"value\": \"fetchTableList\",\n\t\t\t\t\t\t\t\"description\": \"追加了YAPI数据则不使用此参数\",\n\t\t\t\t\t\t\t\"themeCss\": {\n\t\t\t\t\t\t\t\t\"labelClassName\": {\n\t\t\t\t\t\t\t\t\t\"padding-and-margin:default\": {\n\t\t\t\t\t\t\t\t\t\t\"marginTop\": \"\",\n\t\t\t\t\t\t\t\t\t\t\"marginRight\": \"\",\n\t\t\t\t\t\t\t\t\t\t\"marginBottom\": \"\",\n\t\t\t\t\t\t\t\t\t\t\"marginLeft\": \"\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"labelClassName\": \"labelClassName-a3e712484fae\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"label\": \"接口数据字段 PATH\",\n\t\t\t\t\t\t\t\"name\": \"result\",\n\t\t\t\t\t\t\t\"id\": \"u:8c082acf7db2\",\n\t\t\t\t\t\t\t\"value\": \"[\\\"result\\\"][\\\"records\\\"]\",\n\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"label\": \"service方法名\",\n\t\t\t\t\t\t\t\"name\": \"serviceName\",\n\t\t\t\t\t\t\t\"id\": \"u:cfbbdd07366b\",\n\t\t\t\t\t\t\t\"value\": \"getTableList\",\n\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\t\"id\": \"u:382f8cdf59a6\",\n\t\t\t\t\t\"collapsed\": true,\n\t\t\t\t\t\"className\": \"\",\n\t\t\t\t\t\"headingClassName\": \"\",\n\t\t\t\t\t\"bodyClassName\": \"p-r p-l p-b\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"fieldset\",\n\t\t\t\t\t\"title\": \"新增/编辑弹框\",\n\t\t\t\t\t\"collapsable\": true,\n\t\t\t\t\t\"body\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\"label\": \"是否包含弹框\",\n\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\"name\": \"includeModifyModal\",\n\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\"id\": \"u:03957070af9e\",\n\t\t\t\t\t\t\t\"value\": false\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"combo\",\n\t\t\t\t\t\t\t\"label\": \"表单项\",\n\t\t\t\t\t\t\t\"name\": \"modifyModal.formItems\",\n\t\t\t\t\t\t\t\"multiple\": true,\n\t\t\t\t\t\t\t\"addable\": true,\n\t\t\t\t\t\t\t\"removable\": true,\n\t\t\t\t\t\t\t\"removableMode\": \"icon\",\n\t\t\t\t\t\t\t\"strictMode\": false,\n\t\t\t\t\t\t\t\"addBtn\": {\n\t\t\t\t\t\t\t\t\"label\": \"新增\",\n\t\t\t\t\t\t\t\t\"icon\": \"fa fa-plus\",\n\t\t\t\t\t\t\t\t\"level\": \"primary\",\n\t\t\t\t\t\t\t\t\"size\": \"sm\",\n\t\t\t\t\t\t\t\t\"id\": \"u:86cc27b6a663\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"items\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"key\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:62cc1cf36c73\",\n\t\t\t\t\t\t\t\t\t\"label\": \"字段名（key）\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\"name\": \"type\",\n\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"string\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"number\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"number\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"boolean\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"Dayjs\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"Dayjs\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"string[]\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"string[]\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"number[]\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"number[]\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"boolean[]\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"boolean[]\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"[Dayjs,Dayjs]\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"[Dayjs,Dayjs]\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"id\": \"u:b165c75e5e1a\",\n\t\t\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\t\t\"label\": \"字段类型\",\n\t\t\t\t\t\t\t\t\t\"value\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"字段可选\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"optional\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:68fc4c85fb03\",\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"字段名字后加?\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\"name\": \"defaultValue\",\n\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"\\\"\\\"\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"\\\"\\\"\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"false\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"false\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"true\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"true\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"0\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"0\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"undefined\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"undefined\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"[]\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"[]\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"id\": \"u:379ea92fb3c6\",\n\t\t\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\t\t\"label\": \"默认值\",\n\t\t\t\t\t\t\t\t\t\"value\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\"name\": \"component\",\n\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"input\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"input\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"input-password\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"input-password\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"input-number\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"input-number\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"textarea\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"textarea\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"select\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"select\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"radio-group\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"radio-group\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"checkbox-group\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"checkbox-group\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"switch\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"switch\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"date-picker\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"date-picker\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"time-ticker\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"time-picker\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"range-picker\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"range-picker\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"transfer\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"transfer\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"id\": \"u:7932ea3b05da\",\n\t\t\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\t\t\"label\": \"组件\",\n\t\t\t\t\t\t\t\t\t\"value\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"label\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:5bb237f20098\",\n\t\t\t\t\t\t\t\t\t\"label\": \"label\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"placeholder\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:580898257491\",\n\t\t\t\t\t\t\t\t\t\"label\": \"placeholder\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"required\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"required\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:559dbdbb01da\",\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"验证规则加required\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"message\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:55013279d659\",\n\t\t\t\t\t\t\t\t\t\"label\": \"校验失败 message\",\n\t\t\t\t\t\t\t\t\t\"value\": \"不能为空\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"更多组件配置\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"showMore\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:67e0cb5b7496\",\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"labelInValue\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"labelInValue\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:7fd6f1b233d9\",\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"是否把每个选项的 label 包装到 value 中\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'select'}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\"name\": \"mode\",\n\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"multiple\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"multiple\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"tags\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"tags\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\t\t\"label\": \"mode\",\n\t\t\t\t\t\t\t\t\t\"value\": \"\",\n\t\t\t\t\t\t\t\t\t\"description\": \"设置 Select 的模式为多选或标签\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'select'}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"optionFilterProp\",\n\t\t\t\t\t\t\t\t\t\"label\": \"optionFilterProp\",\n\t\t\t\t\t\t\t\t\t\"description\": \"搜索时过滤对应的 option 属性\",\n\t\t\t\t\t\t\t\t\t\"value\": \"label\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'select'}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"showSearch\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"showSearch\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"使单选模式可搜索\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'select'}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"hideArrow\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"hideArrow\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"是否隐藏下拉小箭头\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'select'}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"maxlength\",\n\t\t\t\t\t\t\t\t\t\"label\": \"maxlength\",\n\t\t\t\t\t\t\t\t\t\"description\": \"最大长度\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'input' && modifyModal.formItems[index].component !== 'input-password' && modifyModal.formItems[index].component !== 'textarea')}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"showCount\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"showCount\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"是否展示字数\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'input' && modifyModal.formItems[index].component !== 'input-password' && modifyModal.formItems[index].component !== 'textarea')}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"max\",\n\t\t\t\t\t\t\t\t\t\"label\": \"max\",\n\t\t\t\t\t\t\t\t\t\"description\": \"最大值\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'input-number'}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"min\",\n\t\t\t\t\t\t\t\t\t\"label\": \"min\",\n\t\t\t\t\t\t\t\t\t\"description\": \"最小值\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'input-number'}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"step\",\n\t\t\t\t\t\t\t\t\t\"label\": \"step\",\n\t\t\t\t\t\t\t\t\t\"description\": \"每次改变步数，可以为小数\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'input-number'}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"checkedChildren\",\n\t\t\t\t\t\t\t\t\t\"label\": \"checkedChildren\",\n\t\t\t\t\t\t\t\t\t\"description\": \"选中时的内容\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'switch'}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"unCheckedChildren\",\n\t\t\t\t\t\t\t\t\t\"label\": \"unCheckedChildren\",\n\t\t\t\t\t\t\t\t\t\"description\": \"非选中时的内容\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'switch'}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"checkedValue\",\n\t\t\t\t\t\t\t\t\t\"label\": \"checkedValue\",\n\t\t\t\t\t\t\t\t\t\"description\": \"选中时的值\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'switch'}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"unCheckedValue\",\n\t\t\t\t\t\t\t\t\t\"label\": \"unCheckedValue\",\n\t\t\t\t\t\t\t\t\t\"description\": \"非选中时的值\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'switch'}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\"name\": \"picker\",\n\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"date\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"date\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"week\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"week\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"month\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"month\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"quarter\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"quarter\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"year\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"year\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\t\t\"label\": \"picker\",\n\t\t\t\t\t\t\t\t\t\"description\": \"设置选择器类型\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'date-picker' && modifyModal.formItems[index].component !== 'range-picker')}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"showTime\",\n\t\t\t\t\t\t\t\t\t\"name\": \"showTime\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"增加时间选择功能\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'date-picker' && modifyModal.formItems[index].component !== 'range-picker' || modifyModal.formItems[index].picker !== 'date')}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"showNow\",\n\t\t\t\t\t\t\t\t\t\"name\": \"showNow\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"当设定了 showTime 的时候，面板是否显示“此刻”按钮\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'date-picker' && modifyModal.formItems[index].component !== 'range-picker' || modifyModal.formItems[index].picker !== 'date')}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"showToday\",\n\t\t\t\t\t\t\t\t\t\"name\": \"showToday\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"是否展示“今天”按钮\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'date-picker' && modifyModal.formItems[index].component !== 'range-picker' || modifyModal.formItems[index].picker !== 'date')}\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"syncFields\": [],\n\t\t\t\t\t\t\t\"tabsMode\": true,\n\t\t\t\t\t\t\t\"draggable\": true,\n\t\t\t\t\t\t\t\"draggableTip\": \"可拖动排序\",\n\t\t\t\t\t\t\t\"tabsStyle\": \"line\",\n\t\t\t\t\t\t\t\"tabsLabelTpl\": \"表单项${index+1}\",\n\t\t\t\t\t\t\t\"multiLine\": true,\n\t\t\t\t\t\t\t\"noBorder\": false,\n\t\t\t\t\t\t\t\"hiddenOn\": \"${!includeModifyModal}\"\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\t\"bodyClassName\": \"p\",\n\t\t\t\t\t\"collapsed\": true\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"submitText\": \"\"\n\t\t}\n\t],\n\t\"pullRefresh\": {\n\t\t\"disabled\": true\n\t},\n\t\"regions\": [\n\t\t\"body\"\n\t],\n\t\"style\": {\n\t\t\"boxShadow\": \" 0px 0px 0px 0px transparent\"\n\t},\n\t\"asideResizor\": false\n}"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uTools 动态表单/config/schema.ts",
    "content": "export type PageConfig = {\n  filters: {\n    component: string;\n    /**\n     * @description 翻译成英文，驼峰格式\n     * @type {string}\n     */\n    key: string;\n    /**\n     * @description 保持原始内容，不要翻译\n     * @type {string}\n     */\n    label: string;\n    /**\n     * @description 保持原始内容，不要翻译\n     * @type {string}\n     */\n    placeholder: string;\n  }[];\n  columns: {\n    slot: boolean;\n    /**\n     * @description 保持原始内容，不要翻译\n     * @type {string}\n     */\n    title: string;\n    /**\n     * @description 翻译成英文，驼峰格式\n     * @type {string}\n     */\n    dataIndex: string;\n    /**\n     * @description 翻译成英文，驼峰格式\n     * @type {string}\n     */\n    key: string;\n  }[];\n  pagination: {\n    show: boolean;\n    page: string;\n    size: string;\n    total: string;\n  };\n  includeModifyModal: boolean;\n  fetchName: string;\n  result: string;\n  serviceName: string;\n};\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uTools 动态表单/script/index.ts.ejs",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uTools 动态表单/script/src/controller.ts.ejs",
    "content": "import path from 'path';\nimport * as fs from 'fs-extra';\nimport * as execa from 'execa';\nimport * as ejs from 'ejs';\nimport axios from 'axios';\nimport { clipboard } from 'electron';\nimport { generalBasic } from '@share/BaiduOCR/index';\nimport { renderEjsTemplates } from '@share/utils/ejs';\nimport { typescriptToMock } from '@share/utils/platformIndependent/json';\nimport { getShareData } from '@share/utils/shareData';\nimport { MethodHandle } from '@share/uTools/webviewBaseController';\nimport { getBlockJsonValidSchema } from '@share/utils/uTools';\n\nexport const initFiltersFromImage: MethodHandle = async (data) => {\n  const availableFormats = clipboard.availableFormats('clipboard');\n  if (!availableFormats.some((s) => s.includes('image'))) {\n    throw new Error('剪贴板里没有截图');\n  }\n  const base64 = clipboard.readImage('clipboard').toDataURL();\n  const ocrRes = await generalBasic({ image: base64 });\n  return {\n    updateModelImmediately: false,\n    model: data.model,\n    onlyUpdateParams: true,\n    params: ocrRes.words_result.map((s) => s.words).join('\\r\\n'),\n  };\n};\n\nexport const initFiltersFromText: MethodHandle = async (data) => {\n  const filters = data.params\n    .replace(/\\r\\n/g, '\\n')\n    .replace(/\\r/g, '\\n')\n    .split('\\n');\n  const formatedFilters = filters.map((item) => {\n    const s = item.replace(/：|：/g, ':').split(':');\n    return {\n      component: (s[1] || '').indexOf('选择') > -1 ? 'select' : 'input',\n      key: s[0].trim(),\n      label: s[0].trim(),\n      placeholder: s[1] || '',\n    };\n  });\n  return {\n    updateModelImmediately: false,\n    onlyUpdateParams: false,\n    params: '',\n    model: { ...data.model, filters: formatedFilters },\n  };\n};\n\nexport const initColumnsFromText: MethodHandle = async (data) => {\n  const columns = data.params\n    .replace(/\\r\\n/g, '\\n')\n    .replace(/\\r/g, '\\n')\n    .split('\\n');\n  const formatedColumns = columns.map((s) => ({\n    slot: false,\n    title: s,\n    dataIndex: s,\n    key: s,\n  }));\n  return {\n    updateModelImmediately: false,\n    onlyUpdateParams: false,\n    params: '',\n    model: { ...data.model, columns: formatedColumns },\n  };\n};\n\nexport const openChatGPT: MethodHandle = async (data) => {\n  const schema = getBlockJsonValidSchema(data.scriptFile);\n  const clipboardText = JSON.stringify(data.model);\n  const typeName = 'PageConfig';\n  const requestPrompt =\n    `You are a service that translates user requests into JSON objects of type \"${typeName}\" according to the following TypeScript definitions:\\n` +\n    `\\`\\`\\`\\n${schema}\\`\\`\\`\\n` +\n    `The following is a user request:\\n` +\n    `\"\"\"\\n${clipboardText}\\n\"\"\"\\n` +\n    `The following is the user request translated into a JSON object with 2 spaces of indentation and no properties with the value undefined:\\n`;\n  return {\n    updateModelImmediately: true,\n    onlyUpdateParams: false,\n    params: '',\n    showChat: true,\n    chatContent: requestPrompt,\n    model: data.model,\n  };\n};\n\nexport const generateCode: MethodHandle = async (data) => {\n  const { selectedFolder, activeWindow } = getShareData();\n  const tempWorkPath = path.join(activeWindow || '', '.lowcode');\n  const blockPath = path.join(\n    data.scriptFile\n      .replace('/script/src/mainBundle', '')\n      .replace('/script/src/main', ''),\n  );\n  fs.copySync(blockPath, tempWorkPath);\n  try {\n    await renderEjsTemplates(\n      {\n        ...data.model,\n        createBlockPath: path.join(selectedFolder || '').replace(/\\\\/g, '/'),\n      },\n      path.join(tempWorkPath, 'src'),\n    );\n\n    // #region 更新 mock 服务\n    const mockType = fs\n      .readFileSync(path.join(tempWorkPath, 'src', 'temp.mock.type').toString())\n      .toString();\n    fs.removeSync(path.join(tempWorkPath, 'src', 'temp.mock.type'));\n    const { mockCode, mockData } = typescriptToMock(mockType);\n    const mockTemplate = fs\n      .readFileSync(\n        path.join(tempWorkPath, 'src', 'temp.mock.script').toString(),\n      )\n      .toString();\n    fs.removeSync(path.join(tempWorkPath, 'src', 'temp.mock.script'));\n    const mockScript = ejs.render(mockTemplate, {\n      ...data.model,\n      mockCode,\n      mockData,\n      createBlockPath: selectedFolder?.replace(':', ''),\n    });\n    const mockProjectPathRes = await axios\n      .get('http://localhost:3000/mockProjectPath', { timeout: 1000 })\n      .catch(() => {\n        // window.showInformationMessage(\n        //   '获取 mock 项目路径失败，跳过更新 mock 服务',\n        // );\n      });\n    if (mockProjectPathRes?.data.result) {\n      const projectName = activeWindow?.replace(/\\\\/g, '/').split('/').pop();\n      const mockRouteFile = path.join(\n        mockProjectPathRes.data.result,\n        `${projectName}.js`,\n      );\n      let mockFileContent = `\n\t import KoaRouter from 'koa-router';\n\t import proxy from '../middleware/Proxy';\n\t import { delay } from '../lib/util';\n\n\t const Mock = require('mockjs');\n\n\t const { Random } = Mock;\n\n\t const router = new KoaRouter();\n\t router{{mockScript}}\n\t module.exports = router;\n\t `;\n\n      if (fs.existsSync(mockRouteFile)) {\n        mockFileContent = fs.readFileSync(mockRouteFile).toString().toString();\n        const index = mockFileContent.lastIndexOf(')') + 1;\n        mockFileContent = `${mockFileContent.substring(\n          0,\n          index,\n        )}{{mockScript}}\\n${mockFileContent.substring(index)}`;\n      }\n      mockFileContent = mockFileContent.replace(/{{mockScript}}/g, mockScript);\n      fs.writeFileSync(mockRouteFile, mockFileContent);\n      try {\n        execa.sync('node', [\n          path.join(\n            mockProjectPathRes.data.result\n              .replace(/\\\\/g, '/')\n              .replace('/src/routes', ''),\n            '/node_modules/eslint/bin/eslint.js',\n          ),\n          mockRouteFile,\n          '--resolve-plugins-relative-to',\n          mockProjectPathRes.data.result\n            .replace(/\\\\/g, '/')\n            .replace('/src/routes', ''),\n          '--fix',\n        ]);\n      } catch (err) {\n        console.log(err);\n      }\n      // #endregion\n    }\n  } catch (ex) {\n    fs.removeSync(tempWorkPath);\n    throw ex;\n  }\n\n  fs.copySync(path.join(tempWorkPath, 'src'), path.join(selectedFolder || ''));\n  fs.removeSync(tempWorkPath);\n\n  return {\n    updateModelImmediately: false,\n    model: data.model,\n    onlyUpdateParams: true,\n    params: `代码生成目录：${selectedFolder}`,\n  };\n};\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uTools 动态表单/script/src/main.ts.ejs",
    "content": "import { clipboard } from 'electron';\nimport {\n  AskChatGPTForDynamicFormPageWebviewData,\n  MethodHandle,\n  baseAskChatGPTForDynamicFormPage,\n} from '@share/uTools/webviewBaseController';\nimport * as controller from './controller';\n\nexport const bootstrap = async (scriptFile?: string) => {\n  utools.redirect(['lowcode', 'lowcode'], {\n    type: 'text',\n    data: JSON.stringify({ scriptFile, route: '/dynamicForm' }),\n  });\n};\n\n// #region 给 webview 调用的\nexport { getDynamicForm } from '@share/uTools/webviewBaseController';\n\nexport const askChatGPTForDynamicFormPage = (\n  data: AskChatGPTForDynamicFormPageWebviewData,\n) => {\n  return baseAskChatGPTForDynamicFormPage({\n    ...data,\n    validateJsonSchemaTypeName: 'PageConfig',\n  });\n};\n\nexport const runDynamicFormScript: MethodHandle = (data) => {\n  if (controller[data.method]) {\n    return controller[data.method](data);\n  }\n  return Promise.reject(`方法不存在：${data.method}`);\n};\n\n// #endregion\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uTools 动态表单/src/api.ts.keep.ejs",
    "content": "import { request } from \"@/utils/request\";\n<% if (locals.api) { %>\n// #region <%= api.title %>\n<%= type %>\n\n<% if (api.req_query.length > 0 || api.req_params.length > 0 || api.query_path.params.length > 0) { _%>\nexport interface I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Params {\n\t<% api.req_query.filter(query => query.name !== pagination.page && query.name !== pagination.size).map(query => { _%>\n\t\t<%= query.name %>?: string;\n\t<% }) _%>\n\t<% api.req_params.filter(s => s.name !== pagination.page && s.name !== pagination.size).map(query => { _%>\n\t\t<%= query.name %>?: string;\n\t<% }) _%>\n\t<% api.query_path.params.filter(s => s.name !== pagination.page && s.name !== pagination.size).map(query => { _%>\n\t\t<%= query.name %>?: string;\n\t<% }) _%>\n\t<% if (pagination.show) { _%>\n\t\t<%= pagination.page %>: number;\n\t\t<%= pagination.size %>: number;\n\t<% } _%>\n}\n<% } %> \n<% if (requestBodyType && api.req_body_other.indexOf('{}') < 0) { %>\n    <%= requestBodyType %> \n<% } %> \n\n/**\n* <%= api.title %> \n* /project/<%= api.project_id %>/interface/api/<%= api._id %> \n* @author <%= api.username %>  \n* \n<% if (api.req_query.length > 0 || api.req_params.length > 0 || api.query_path.params.length > 0) { -%>* @param {I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Params} params<%- \"\\n\" %><% } _%>\n<% if (requestBodyType && api.req_body_other.indexOf('{}')<0) { -%>* @param {I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Data} data<%- \"\\n\" %><% } _%>\n* @returns\n*/\nexport function <%= funcName %> (\n<% if (api.req_query.length>0 || api.req_params.length > 0 || api.query_path.params.length > 0) { %>\nparams: I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Params,\n<% } _%>\n<% if (requestBodyType) { %> \ndata: I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Data\n<% } %> \n) {\nreturn request<<%= typeName %>>({\n\t  url: `http://127.0.0.1:3000<%= api.query_path.path.replace(/\\{/g,\"${params.\") %>`, \n\t\tmethod: '<%= api.method %>',\n\t\t<% if(api.req_query.length>0 || api.req_params.length > 0) { %>params,<% } _%>\n        <% if (requestBodyType && api.req_body_other.indexOf('{}')<0) {%>data,<% } %> \n\t})\n}\n// #endregion\n<% } else { %>\n// #region\nexport interface I<%= fetchName.slice(0, 1).toUpperCase() + fetchName.slice(1) %>Result {\n  code: number;\n\tmsg: string;\n\t<% if (!pagination.show) { _%>\n\tresult: {\n\t\t<% columns.map((item, index) => { _%>\n\t\t\t<%= item.key || `column${index+1}` %>: string;\n\t\t<% }) _%>\n\t\t}[];\n\t<% } else { _%>\n\t\tresult: {\n\t\t\trecords: {\n\t\t\t\t<% columns.map((item, index) => { _%>\n\t\t\t\t\t<%= item.key || `column${index+1}` %>: string;\n\t\t\t\t<% }) _%>\n\t\t\t}[];\n\t\t\ttotal: number;\n\t\t}\n\t<% } _%>\n}\n\nexport interface I<%= fetchName.slice(0, 1).toUpperCase() + fetchName.slice(1) %>Params {\n\t<% filters.map(item => { _%>\n\t\t<% if(item.component !== \"range-picker\") { _%>\n\t\t\t <%= item.key %>?: string;\n\t\t<% } else { _%>\n\t\t\t<%= item.key %>Start?: string;\n\t\t\t<%= item.key %>End?: string;\n\t\t<% } _%>\n\t<% }) _%>\n\t<% if (pagination.show) { _%>\n\t\t<%= pagination.page %>: number;\n\t\t<%= pagination.size %>: number;\n\t<% } _%>\n}\n\nexport function <%= fetchName %>(\nparams: I<%= fetchName.slice(0, 1).toUpperCase() + fetchName.slice(1) %>Params\n) {\nreturn request<I<%= fetchName.slice(0, 1).toUpperCase() + fetchName.slice(1) %>Result>({\n\turl: `http://127.0.0.1:3000<%= createBlockPath %>/<%= fetchName %>`, \n\tmethod: \"GET\",\n\tparams,\n});\n}\n// #endregion\n<% } %>"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uTools 动态表单/src/index.vue.keep.ejs",
    "content": "<template>\n  <a-row class=\"filterForm\" :gutter=\"30\">\n    <% filters.map(item => { _%> \n\t\t  <a-col :xs=\"24\" :sm=\"24\" :md=\"12\" :lg=\"12\" :xl=\"8\" :xxl=\"6\">\n\t\t\t\t<% if(item.component === \"select\") { %>\n\t\t\t\t<a-form-item label=\"<%= item.label %>\">\n\t\t\t\t\t<a-select\n\t\t\t\t\t\tv-model:value=\"model.filterForm.<%= item.key %>\"\n\t\t\t\t\t\t:options=\"model.options.<%= item.key %>\"\n\t\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\t\tshow-search\n\t\t\t\t\t\tallow-clear\n\t\t\t\t\t\t<% if(item.remoteFetch) { _%>\n\t\t\t\t\t\t:filter-option=\"false\"\n\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\toption-filter-prop=\"label\"\n\t\t\t\t\t\t@change=\"presenter.handleSearch\"\n\t\t\t\t\t\t<% if(item.remoteFetch) { _%>\n\t\t\t\t\t\t@search=\"presenter.handleSearch<%= item.key.slice(0, 1).toUpperCase() + item.key.slice(1) %>\"\n\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t></a-select>\n\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%> \n\t\t\t\t<% if(item.component === \"input\") { _%>\n\t\t\t\t<a-form-item label=\"<%= item.label %>\">\n\t\t\t\t\t<a-input\n\t\t\t\t\t\tv-model:value=\"model.filterForm.<%= item.key %>\"\n\t\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\t\tallow-clear\n\t\t\t\t\t\t@press-enter=\"presenter.handleSearch\"\n\t\t\t\t\t></a-input>\n\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%> \n\t\t\t\t<% if(item.component === \"range-picker\") { _%>\n\t\t\t\t<a-form-item label=\"<%= item.label %>\">\n\t\t\t\t\t<a-range-picker\n\t\t\t\t\t\tv-model:value=\"model.filterForm.<%= item.key %>\"\n\t\t\t\t\t\t:placeholder=\"['开始时间', '结束时间']\"\n\t\t\t\t\t\tformat=\"YYYY-MM-DD\"\n\t\t\t\t\t\tvalueFormat=\"YYYY-MM-DD\"\n\t\t\t\t\t\t@change=\"presenter.handleSearch\"\n\t\t\t\t\t/>\n\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%> \n\t\t\t</a-col>\n\t\t<% }) _%>\n\t\t<a-col style=\"text-align: right; flex: 1\">\n\t\t\t<a-space>\n\t\t\t\t<a-button @click=\"presenter.handleClear\">重置</a-button>\n        <a-button @click=\"presenter.handleSearch\" type=\"primary\">查询</a-button>\n        <a-button @click=\"presenter.handleCreate\" type=\"primary\">\n          <template #icon><PlusOutlined /></template>\n          新增\n        </a-button>\n\t\t\t</a-space>\n\t\t</a-col>\n  </a-row>\n  <a-table\n    :loading=\"model.loading.list\"\n    :columns=\"columns\"\n    :data-source=\"model.tableList.value\"\n    :pagination=\"false\"\n  >\n\t\t<template #bodyCell=\"{ column, record }\">\n\t\t\t<% columns.filter(item => item.slot).map((item, index) => { _%>\n\t\t\t\t<template v-if=\"column.key === '<%= item.key %>'\">\n\t\t\t\t\t{{ record.<%= item.key %> }}\n\t\t\t\t</template>\n\t\t\t<% }) _%>\n\t\t\t<template v-if=\"column.key === 'operation'\">\n\t\t\t\t<a-space :size=\"0\">\n\t\t\t\t\t<% if(includeModifyModal) { _%>\n\t\t\t\t\t<a-button\n\t\t\t\t\t\ttype=\"link\"\n\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t@click=\"\n\t\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\t\tpresenter.handleView(record);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\"\n\t\t\t\t\t>\n\t\t\t\t\t\t查看\n\t\t\t\t\t</a-button>\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<a-button\n\t\t\t\t\t\ttype=\"link\"\n\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t@click=\"\n\t\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\t\tpresenter.handleEdit(record);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\"\n\t\t\t\t\t>\n\t\t\t\t\t\t编辑\n\t\t\t\t\t</a-button>\n\t\t\t\t\t<a-button\n\t\t\t\t\t\ttype=\"link\"\n\t\t\t\t\t\tdanger\n\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t@click=\"\n\t\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\t\tpresenter.handleDel(record);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\"\n\t\t\t\t\t>\n\t\t\t\t\t\t删除\n\t\t\t\t\t</a-button>\n\t\t\t\t</a-space>\n\t\t\t</template>\n\t\t</template>\n  </a-table>\n  <% if(pagination.show) { _%>\n  <a-pagination\n    style=\"margin-top: 10px\"\n    @change=\"presenter.handlePageChange\"\n\t@showSizeChange=\"presenter.handlePageChange\"\n    v-model:current=\"model.pagination.page\"\n    :total=\"model.pagination.total\"\n    show-size-changer\n    show-quick-jumper\n\t:show-total=\"(total: number) => `共 ${total} 条`\"\n  ></a-pagination>\n  <% } _%> <% if(includeModifyModal) { _%>\n  <ModifyModal\n    :id=\"model.modalInfo.id\"\n    :title=\"model.modalInfo.title\"\n    :visible=\"model.modalInfo.visible\"\n    :action=\"model.modalInfo.action\"\n    @ok=\"presenter.handleModalOk\"\n    @cancel=\"presenter.handleModalCancel\"\n  ></ModifyModal>\n  <% } _%>\n</template>\n<script lang=\"ts\" setup>\n  import { PlusOutlined } from \"@ant-design/icons-vue\";\n  <% if(includeModifyModal) { _%>\n  import ModifyModal from \"./ModifyModal/index.vue\";\n  <% } _%>\n  import { usePresenter } from \"./presenter\";\n\n  const presenter = usePresenter();\n  const { model } = presenter;\n\n  const columns = [\n    <% columns.map((item, index) => { _%>\n  \t\t{\n        title: \"<%= item.title || `column${index+1}` %>\",\n  \t\t\tdataIndex: \"<%= item.dataIndex || `column${index+1}` %>\",\n  \t\t\tkey: \"<%= item.key || `column${index+1}` %>\",\n  \t\t\t<% if(item.width) {%>width: \"<%= item.width %>\",<% } _%>\n  \t\t},\n  \t<% }) _%>\n  \t{\n      title: \"操作\",\n      key: \"operation\",\n  \t\twidth: 100\n    }\n  ];\n</script>\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uTools 动态表单/src/model.ts.keep.ejs",
    "content": "import { reactive, ref } from \"vue\";\n<% if(locals.api){ %>\nimport { I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Result } from \"./api\";\n<% } else { %>\nimport { I<%= fetchName.slice(0, 1).toUpperCase() + fetchName.slice(1) %>Result } from \"./api\";\n<% } %>\n<% if(!locals.api){ %>\ninterface ITableListItem {\n\t<% columns.map((item, index) => { _%>\n\t\t/** <%= item.title %> */\n\t\t<%= item.key || `column${index+1}` %>: string;\n\t<% }) _%>\n\t/**\n   * 接口返回的数据，新增字段不需要改 ITableListItem 直接从这里取\n   */\n\tapiResult: I<%= fetchName.slice(0, 1).toUpperCase() + fetchName.slice(1) %>Result<%- result %>[0]\n}\n<% } %>\ninterface IFormData {\n\t<% filters.map(item => { _%>\n\t\t/** <%= item.label %> */\n\t\t<% if(item.component === \"range-picker\") { _%>\n\t\t\t<%= item.key %>?: [string,string];\n\t\t<% } _%>\n\t\t<% if(item.component !== \"range-picker\") { _%>\n\t\t\t<%= item.key %>?: string;\n\t\t<% } _%>\n\t<% }) _%>\n}\n<% if(filters.some(s => s.component === \"select\" )){ %>\ninterface IOptionItem {\n  label: string;\n  value: string;\n}\n\ninterface IOptions {\n  <% filters.filter(s => s.component === \"select\").map(item => { _%>\n\t<%= item.key %>: IOptionItem[],\n  <% }) _%>\n}\n\nconst defaultOptions: IOptions = {\n\t<% filters.filter(s => s.component === \"select\").map(item => { _%>\n\t\t<%= item.key %>: [],\n\t<% }) _%>\n};\n<% } %>\nexport const defaultFormData: IFormData = {\n\t<% filters.map(item => { _%>\n\t\t<%= item.key %>: undefined,\n\t<% }) _%>\n};\n\nexport const useModel = () => {\n  const filterForm = reactive<IFormData>({ ...defaultFormData });\n\t<% if(filters.some(s => s.component === \"select\" )){ %>\n  \t\tconst options = reactive<IOptions>({ ...defaultOptions });\n\t<% } %>\n\t<% if(locals.api){ _%>\n\t\tconst tableList = ref<(I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Result<%- result %>[0] & { _?: unknown })[]>(\n\t\t\t[],\n\t\t);\n\t<% } else { _%>\n\t\tconst tableList = ref<(ITableListItem & { _?: unknown })[]>(\n\t\t\t[],\n\t\t);\n\t<% } _%>\n\t<% if(pagination.show) { %>\n\t\tconst pagination = reactive<{\n\t\t\tpage: number;\n\t\t\tpageSize: number;\n\t\t\ttotal: number;\n\t\t}>({\n\t\t\tpage: 1,\n\t\t\tpageSize: 10,\n\t\t\ttotal: 0,\n\t\t});\n\t<% } %>\n  const loading = reactive<{ list: boolean }>({\n    list: false,\n  });\n  <% if(includeModifyModal) { %>\n\tconst modalInfo = reactive<{\n\t\tvisible: boolean;\n\t\ttitle: string;\n\t\tid?: number;\n\t\taction: \"add\" | \"edit\" | \"view\";\n\t}>({\n\t\tvisible: false,\n\t\ttitle: \"\",\n\t\taction: \"add\",\n\t});\n  <% } %>\n  return {\n    filterForm,\n\t\t<% if(filters.some(s => s.component === \"select\" )){ _%>\n    options,\n\t\t<% } _%>\n    tableList,\n\t\t<% if(pagination.show) { _%>\n\t\tpagination,\n\t\t<% } _%>\n\t\t\tloading,\n\t\t<% if(includeModifyModal) { _%>\n\t\tmodalInfo,\n\t\t<% } _%>\n  };\n};\n\nexport type Model = ReturnType<typeof useModel>;\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uTools 动态表单/src/presenter.ts.keep.ejs",
    "content": "import Service from \"./service\";\nimport { defaultFormData, useModel } from \"./model\";\nimport { createVNode, onMounted } from \"vue\";\nimport { message, Modal } from \"ant-design-vue\";\nimport { ExclamationCircleOutlined } from \"@ant-design/icons-vue\";\n<% if(filters.some(item => item.component === \"select\" && item.remoteFetch)) { _%>\nimport { useDebounceFn } from \"@vueuse/core\";\n<% } _%>\n\nexport const usePresenter = () => {\n  const model = useModel();\n  const service = new Service(model);\n\n  onMounted(() => {\n    service.<%= serviceName %>();\n  });\n\n  const handleClear = () => {\n\t\tObject.assign(model.filterForm, defaultFormData)\n\t\t<% if(pagination.show) { _%>\n\t\t\tmodel.pagination.page = 1;\n\t\t<% } _%>\n    service.<%= serviceName %>();\n  };\n\n  const handleSearch = () => {\n\t\t<% if(pagination.show) { _%>\n\t\t\tmodel.pagination.page = 1;\n\t\t<% } _%>\n    service.<%= serviceName %>();\n  };\n\n  <% if(pagination.show) { _%>\n  const handlePageChange = (page: number, pageSize: number) => {\n    if (pageSize !== model.pagination.pageSize) {\n      model.pagination.pageSize = pageSize;\n      model.pagination.page = 1;\n    } else {\n      model.pagination.page = page;\n    }\n    service.<%= serviceName %>();\n  };\n  <% } _%>\n\n\t<% filters.filter(item => item.component === \"select\" && item.remoteFetch).map(item => { _%> \n\tconst handleSearch<%= item.key.slice(0, 1).toUpperCase() + item.key.slice(1) %> = useDebounceFn((value: string) => {\n    if (!value) {\n      return;\n    }\n    service.search<%= item.key.slice(0, 1).toUpperCase() + item.key.slice(1) %>(value);\n  }, 400);\n\t\n\t<% }) _%>\n\n  const handleDel = (record: typeof model.tableList.value[0]) => {\n    Modal.confirm({\n      title: \"此操作将删除该选项，是否继续？\",\n      icon: createVNode(ExclamationCircleOutlined),\n\t\t\tokText: \"确定\",\n      cancelText: \"取消\",\n      onOk() {\n        message.success(\"删除成功\");\n      },\n    });\n  };\n\n  const handleCreate = () => {\n\t<% if(includeModifyModal) { _%>\n    model.modalInfo.visible = true;\n    model.modalInfo.title = \"新建\";\n    model.modalInfo.action = \"add\";\n    model.modalInfo.id = undefined;\n\t<% } _%>\n  };\n\n  const handleEdit = (record: typeof model.tableList.value[0]) => {\n\t<% if(includeModifyModal) { _%>\n    model.modalInfo.visible = true;\n    model.modalInfo.title = \"编辑\";\n    model.modalInfo.action = \"edit\";\n    model.modalInfo.id = record.id;\n\t<% } _%>\n  };\n\n  <% if(includeModifyModal) { _%>\n  const handleView = (record: typeof model.tableList.value[0]) => {\n    model.modalInfo.visible = true;\n    model.modalInfo.title = \"查看\";\n    model.modalInfo.action = \"view\";\n    model.modalInfo.id = record.id;\n  };\n\n  const handleModalOk = () => {\n    model.modalInfo.visible = false;\n    service.<%= serviceName %>();\n  };\n\n  const handleModalCancel = () => {\n    model.modalInfo.visible = false;\n  };\n  <% } _%>\n\n  return {\n    model,\n    service,\n    handleClear,\n    handleSearch,\n\t\t<% if(pagination.show) { _%>\n\t\thandlePageChange,\n    <% } _%>\n\t\t<% filters.filter(item => item.component === \"select\" && item.remoteFetch).map(item => { _%> \n\t\t\thandleSearch<%= item.key.slice(0, 1).toUpperCase() + item.key.slice(1) %>,\n\t\t<% }) _%>\n\thandleDel,\n\thandleCreate,\n    handleEdit,\n\t<% if(includeModifyModal) { _%>\n\thandleView,\n\thandleModalOk,\n\thandleModalCancel\n\t<% } _%>\n  };\n};\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uTools 动态表单/src/service.ts.keep.ejs",
    "content": "import { <%= locals.api ? funcName : fetchName %> } from \"./api\";\nimport { Model } from \"./model\"; \n\nexport default class Service {\n  private model: Model;\n\n  constructor(model: Model) {\n    this.model = model;\n  }\n\n  async <%= serviceName %>() {\n    this.model.loading.list = true;\n\t\t<% filters.map(item => { _%>\n\t\t\t<% if(item.component === \"range-picker\") { _%>\n\t\t\t\tlet <%= item.key %>Start: string | undefined = undefined;\n\t\t\t\tlet <%= item.key %>End: string | undefined = undefined;\n\t\t\t\tif (\n\t\t\t\tthis.model.filterForm.<%= item.key %> &&\n\t\t\t\tthis.model.filterForm.<%= item.key %>[0]\n\t\t\t\t) {\n\t\t\t\t\t<%= item.key %>Start = `${this.model.filterForm.<%= item.key %>[0]} 00:00:00`;\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\tthis.model.filterForm.<%= item.key %> &&\n\t\t\t\tthis.model.filterForm.<%= item.key %>[1]\n\t\t\t\t) {\n\t\t\t\t\t<%= item.key %>End = `${this.model.filterForm.<%= item.key %>[1]} 23:59:59`;\n\t\t\t\t}\n\t\t\t<% } _%>\n\t\t<% }) _%>\n    const res = await <%= locals.api ? funcName : fetchName %>({\n\t\t\t<% filters.map(item => { _%>\n\t\t\t\t<% if(item.component !== \"range-picker\") { _%>\n\t\t\t\t\t<%= item.key %>: this.model.filterForm.<%= item.key %>,\n\t\t\t\t<% } else { _%>\n\t\t\t\t\t<%= item.key %>Start: <%= item.key %>Start,\n\t\t\t\t\t<%= item.key %>End: <%= item.key %>End,\n\t\t\t\t<% } _%>\n\t\t\t<% }) _%>\n\t\t\t<% if(pagination.show) { _%>\n\t\t\t\t<%= pagination.page %>: this.model.pagination.page,\n\t\t\t\t<%= pagination.size %>: this.model.pagination.pageSize,\n\t\t\t<% } _%>\n\t\t}).finally(() => {\n\t\t\tthis.model.loading.list = false;\n\t\t});\n    this.model.tableList.value = res<%- result %>.map((s) => {\n      return {\n\t\t...s,\n\t\t<% columns.map((item, index) => { _%>\n\t\t\t<%= item.key || `column${index+1}` %>: s.<%= item.key || `column${index+1}` %>,\n\t\t<% }) _%>\n\t\tapiResult: s\n      };\n    });\n\t<% if(pagination.show) { _%>\n\tthis.model.pagination.total = res.<%- pagination.total %>;\n\t<% } _%>\n  }\n\n\t<% filters.filter(item => item.component === \"select\" && item.remoteFetch).map(item => { _%> \n\t\tasync search<%= item.key.slice(0, 1).toUpperCase() + item.key.slice(1) %>(value: string) {\n\t\t\tconst res = await Promise.resolve([{ label: \"1\", value: \"1\" }]);\n\t\t\tthis.model.options.<%= item.key %> = res;\n\t\t}\n\t\t\n\t<% }) _%>\n}\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uTools 动态表单/src/temp.mock.script",
    "content": ".get(`<%= createBlockPath %>/<%= fetchName %>`, async (ctx, next) => { <%- mockCode %> ctx.body = <%- mockData %>\n})\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uTools 动态表单/src/temp.mock.type.keep.ejs",
    "content": "{\n  code: number;\n\tmsg: string;\n\t<% if (!pagination.show) { _%>\n\tresult: {\n\t\t<% columns.map((item, index) => { _%>\n\t\t\t<%= item.key || `column${index+1}` %>: string;\n\t\t<% }) _%>\n\t}[];\n\t<% } else { _%>\n\t\tresult: {\n\t\t\trecords: {\n\t\t\t\t<% columns.map((item, index) => { _%>\n\t\t\t\t\t<%= item.key || `column${index+1}` %>: string;\n\t\t\t\t<% }) _%>\n\t\t\t}[];\n\t\t\ttotal: number;\n\t\t}\n\t<% } _%>\n}"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uTools 自动化脚本/script/index.ts.ejs",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uTools 自动化脚本/script/src/main.ts.ejs",
    "content": "import { clipboard } from 'electron';\n\nexport const bootstrap = async (scriptFile?: string) => {\n  utools.redirect(['lowcode', 'lowcode'], {\n    type: 'text',\n    data: JSON.stringify({ scriptFile, route: '/chat' }),\n  });\n};"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uniapp/vue3-mvp/index.scss.ejs",
    "content": ".<%= createBlockPath.split(\"/\").pop().replace(/^\\S/, s => s.toLowerCase()) %> {\n}\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uniapp/vue3-mvp/index.vue.ejs",
    "content": "<template>\n  <view class=\"<%= createBlockPath.split('/').pop().replace(/^\\S/, s => s.toLowerCase()) %>\"></view>\n</template>\n\n<script setup lang=\"ts\">\nimport { usePresenter } from \"./presenter\";\n\n// const presenter = usePresenter();\n// const { model } = presenter;\n</script>\n\n<style scoped lang=\"scss\">\n@import \"./index.scss\";\n</style>\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uniapp/vue3-mvp/model.ts",
    "content": "export const useModel = () => {};\n\nexport type Model = ReturnType<typeof useModel>;\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uniapp/vue3-mvp/presenter.ts",
    "content": "import Service from \"./service\";\nimport { useModel } from \"./model\";\n\nexport const usePresenter = () => {\n  const model = useModel();\n  const service = new Service(model);\n\n  return {\n    model,\n    service,\n  };\n};\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uniapp/vue3-mvp/service.ts",
    "content": "import type { Model } from \"./model\";\n\nexport default class Service {\n  private model: Model;\n\n  constructor(model: Model) {\n    this.model = model;\n  }\n}\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uniapp/vue3-mvp emit/index.scss.ejs",
    "content": ".<%= createBlockPath.split(\"/\").pop().replace(/^\\S/, s => s.toLowerCase()) %> {\n}\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uniapp/vue3-mvp emit/index.vue.ejs",
    "content": "<template>\n  <view class=\"<%= createBlockPath.split('/').pop().replace(/^\\S/, s => s.toLowerCase()) %>\" @click=\"presenter.handleChange('emit')\">emit</view>\n</template>\n\n<script setup lang=\"ts\">\nimport { usePresenter } from \"./presenter\";\n\nconst emit = defineEmits<{\n  (e: \"change\", data?: { value: string }): void;\n}>();\n\nconst presenter = usePresenter(emit);\n// const { model } = presenter;\n</script>\n\n<style scoped lang=\"scss\">\n@import \"./index.scss\";\n</style>\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uniapp/vue3-mvp emit/model.ts",
    "content": "export const useModel = () => {};\n\nexport type Model = ReturnType<typeof useModel>;\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uniapp/vue3-mvp emit/presenter.ts",
    "content": "import Service from \"./service\";\nimport { useModel } from \"./model\";\n\ninterface IEmit {\n  (e: \"change\", data?: { value: string }): void;\n}\n\nexport const usePresenter = (emit: IEmit) => {\n  const model = useModel();\n  const service = new Service(model);\n\n  const handleChange = (value: string) => {\n    emit(\"change\", { value });\n  };\n\n  return {\n    model,\n    service,\n    handleChange,\n  };\n};\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uniapp/vue3-mvp emit/service.ts",
    "content": "import type { Model } from \"./model\";\n\nexport default class Service {\n  private model: Model;\n\n  constructor(model: Model) {\n    this.model = model;\n  }\n}\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uniapp/vue3-mvp props/index.scss.ejs",
    "content": ".<%= createBlockPath.split(\"/\").pop().replace(/^\\S/, s => s.toLowerCase()) %> {\n}\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uniapp/vue3-mvp props/index.vue.ejs",
    "content": "<template>\n  <view class=\"<%= createBlockPath.split('/').pop().replace(/^\\S/, s => s.toLowerCase()) %>\">{{ props.name }}</view>\n</template>\n\n<script setup lang=\"ts\">\nimport { usePresenter } from \"./presenter\";\n\nconst props = defineProps<{ name: string }>();\n\nconst presenter = usePresenter(props);\n// const { model } = presenter;\n</script>\n\n<style scoped lang=\"scss\">\n@import \"./index.scss\";\n</style>\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uniapp/vue3-mvp props/model.ts",
    "content": "export const useModel = () => {};\n\nexport type Model = ReturnType<typeof useModel>;\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uniapp/vue3-mvp props/presenter.ts",
    "content": "import Service from \"./service\";\nimport { useModel } from \"./model\";\n\ninterface IProps {\n  name: string;\n}\n\nexport const usePresenter = (props: IProps) => {\n  const model = useModel();\n  const service = new Service(model);\n\n\n  return {\n    model,\n    service,\n  };\n};\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uniapp/vue3-mvp props/service.ts",
    "content": "import type { Model } from \"./model\";\n\nexport default class Service {\n  private model: Model;\n\n  constructor(model: Model) {\n    this.model = model;\n  }\n}\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uniapp/vue3-mvp props emit/index.scss.ejs",
    "content": ".<%= createBlockPath.split(\"/\").pop().replace(/^\\S/, s => s.toLowerCase()) %> {\n}\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uniapp/vue3-mvp props emit/index.vue.ejs",
    "content": "<template>\n  <view class=\"<%= createBlockPath.split('/').pop().replace(/^\\S/, s => s.toLowerCase()) %>\" @click=\"presenter.handleChange()\">{{ props.name }}</view>\n</template>\n\n<script setup lang=\"ts\">\nimport { usePresenter } from \"./presenter\";\n\nconst props = defineProps<{ name: string }>();\n\nconst emit = defineEmits<{\n  (e: \"change\", data?: { value: string }): void;\n}>();\n\nconst presenter = usePresenter(props, emit);\n// const { model } = presenter;\n</script>\n\n<style scoped lang=\"scss\">\n@import \"./index.scss\";\n</style>\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uniapp/vue3-mvp props emit/model.ts",
    "content": "export const useModel = () => {};\n\nexport type Model = ReturnType<typeof useModel>;\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uniapp/vue3-mvp props emit/presenter.ts",
    "content": "import Service from \"./service\";\nimport { useModel } from \"./model\";\n\ninterface IProps {\n  name: string;\n}\n\ninterface IEmit {\n  (e: \"change\", data?: { value: string }): void;\n}\n\nexport const usePresenter = (props: IProps, emit: IEmit) => {\n  const model = useModel();\n  const service = new Service(model);\n\n  const handleChange = () => {\n    emit(\"change\", { value: props.name });\n  };\n\n  return {\n    model,\n    service,\n    handleChange,\n  };\n};\n"
  },
  {
    "path": "materials/snippets/快速创建区块/src/uniapp/vue3-mvp props emit/service.ts",
    "content": "import type { Model } from \"./model\";\n\nexport default class Service {\n  private model: Model;\n\n  constructor(model: Model) {\n    this.model = model;\n  }\n}\n"
  },
  {
    "path": "materials/snippets/打开webview/config/model.json",
    "content": "{\n  \"name\": \"lowcode\"\n}"
  },
  {
    "path": "materials/snippets/打开webview/config/preview.json",
    "content": "{\n\t\"title\": \"\",\n\t\"description\": \"\",\n\t\"img\": [\n\t\t\"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n\t],\n\t\"category\": [],\n\t\"notShowInCommand\": true,\n\t\"notShowInSnippetsList\": true,\n\t\"notShowInintellisense\": true,\n\t\"showInRunSnippetScript\": true,\n\t\"schema\": \"amis\",\n\t\"scripts\": []\n}"
  },
  {
    "path": "materials/snippets/打开webview/config/schema.json",
    "content": "{\n  \"formSchema\": {\n    \"schema\": {\n      \"type\": \"page\",\n      \"body\": [\n        {\n          \"type\": \"form\",\n          \"title\": \"\",\n          \"body\": [\n            {\n              \"type\": \"input-text\",\n              \"name\": \"name\",\n              \"label\": \"测试表单\",\n              \"id\": \"u:4886baa626cf\",\n              \"value\": \"\"\n            }\n          ],\n          \"id\": \"u:67967afb0e69\",\n          \"submitText\": \"\"\n        }\n      ],\n      \"id\": \"u:d87dbf6bf8df\",\n      \"asideResizor\": false,\n      \"style\": {\n        \"boxShadow\": \" 0px 0px 0px 0px transparent\"\n      },\n      \"pullRefresh\": {\n        \"disabled\": true\n      },\n      \"regions\": [\n        \"body\"\n      ]\n    }\n  }\n}"
  },
  {
    "path": "materials/snippets/打开webview/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/打开webview/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/打开webview/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: (lowcodeContext) => {},\n  onSelect: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    await main.bootstrap();\n  },\n  testScript: (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    return main.testScript();\n  },\n};\n"
  },
  {
    "path": "materials/snippets/打开webview/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { CompileContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/打开webview/script/src/controller.ts",
    "content": "import * as vscode from 'vscode';\nimport { CompileContext } from 'lowcode-context';\nimport { createChatCompletion } from '@share/LLM/gemini';\nimport { createChatCompletion as createChatGPTChatCompletion } from '@share/LLM/openai';\nimport { invokeLLMChunkCallback } from '@share/WebView/callback';\nimport { IMessage } from '@share/WebView/type';\n\nconst API_KEY = 'lowcode.GeminiKey';\n\nexport const getMaterialPath = async (\n  message: IMessage<{\n    materialPath: string;\n    script: string;\n    params: string;\n  }>,\n  context: {\n    webview: vscode.Webview;\n    task: { task: string; data?: any };\n  } & CompileContext,\n) => context.materialPath;\n\ntype Message = (\n  | {\n      role: 'system';\n      content: string;\n    }\n  | {\n      role: 'user';\n      content:\n        | string\n        | (\n            | {\n                type: 'image_url';\n                image_url: { url: string };\n              }\n            | { type: 'text'; text: string }\n          )[];\n    }\n)[];\nexport const askGemini = async (\n  message: IMessage<{\n    messages: Message;\n  }>,\n  lowcodeContext: {\n    webview: vscode.Webview;\n  } & CompileContext,\n) => {\n  const context = lowcodeContext.env.extensionContext;\n  // await context.secrets.delete(API_KEY); // 需要更新 API KEY 的时候打开\n  let apiKey = await context.secrets.get(API_KEY);\n\n  if (!apiKey) {\n    vscode.window.showWarningMessage('Enter your API KEY to save it securely.');\n    apiKey = await setApiKey(context);\n    if (!apiKey) {\n      invokeLLMChunkCallback(lowcodeContext.webview, message.cbid, {\n        content: 'Please enter your api key',\n      });\n      return {\n        content: 'Please enter your api key',\n      };\n    }\n  }\n  const res = await createChatCompletion({\n    model: message.data.messages.some(\n      (s) =>\n        Array.isArray(s.content) &&\n        s.content.some((c) => c.type === 'image_url'),\n    )\n      ? 'gemini-pro-vision'\n      : 'gemini-pro',\n    apiKey,\n    messages: message.data.messages,\n    handleChunk: (data) => {\n      invokeLLMChunkCallback(lowcodeContext.webview, message.cbid, {\n        content: data.text,\n      });\n    },\n    proxyUrl: 'http://127.0.0.1:7890',\n  });\n  return {\n    content: res,\n  };\n};\n\nexport const askChatGPT = async (\n  message: IMessage<{\n    messages: Message;\n  }>,\n  lowcodeContext: {\n    webview: vscode.Webview;\n  } & CompileContext,\n) => {\n  const res = await createChatGPTChatCompletion({\n    model: message.data.messages.some(\n      (s) =>\n        Array.isArray(s.content) &&\n        s.content.some((c) => c.type === 'image_url'),\n    )\n      ? 'gpt-4-vision-preview'\n      : undefined,\n    messages: message.data.messages,\n    handleChunk: (data) => {\n      invokeLLMChunkCallback(lowcodeContext.webview, message.cbid, {\n        content: data.text,\n      });\n    },\n  });\n  return {\n    content: res,\n  };\n};\n\nasync function setApiKey(context) {\n  const apiKey = await vscode.window.showInputBox({\n    title: 'Enter your API KEY',\n    password: true,\n    placeHolder: '**************************************',\n    ignoreFocusOut: true,\n  });\n\n  if (!apiKey) {\n    vscode.window.showWarningMessage('Empty value');\n    return;\n  }\n\n  await context.secrets.store(API_KEY, apiKey);\n  return apiKey;\n}\n"
  },
  {
    "path": "materials/snippets/打开webview/script/src/main.ts",
    "content": "import { window } from 'vscode';\nimport { showWebView } from '@share/WebView';\nimport { routes } from './routes';\nimport { context } from './context';\n\nexport async function bootstrap() {\n  const { lowcodeContext } = context;\n  showWebView({\n    key: 'main',\n    title: 'lowcode chat',\n    viewColumn: 3,\n    task: {\n      task: 'route',\n      data: { path: '/chat', materialPath: lowcodeContext?.materialPath },\n    },\n    lowcodeContext: {\n      ...lowcodeContext!,\n    },\n    htmlForWebview: getHtmlForWebview(false),\n    routes,\n  });\n}\n\nexport async function testScript() {\n  const { lowcodeContext } = context;\n  window.showInformationMessage('Hello World!');\n  const res = await lowcodeContext?.createChatCompletion({\n    messages: [{ role: 'user', content: '现在是什么时间' }],\n    showWebview: true,\n  });\n  return res;\n}\n\nconst getHtmlForWebview = (dev = false) => {\n  if (dev) {\n    // return `\n    // \t<!doctype html>\n    // \t<html lang=\"en\">\n    // \t\t<head>\n    // \t\t\t<script type=\"module\" src=\"http://127.0.0.1:5173/@vite/client\"></script>\n    // \t    <script>\n    // \t\t\t\twindow.vscode = acquireVsCodeApi();\n    // \t\t\t</script>\n    // \t\t\t<meta charset=\"UTF-8\" />\n    // \t\t\t<link rel=\"icon\" type=\"image/svg+xml\" href=\"http://127.0.0.1:5173/vite.svg\" />\n    // \t\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    // \t\t\t<title>Vite + Vue + TS</title>\n    // \t\t</head>\n    // \t\t<body>\n    // \t\t\t<div id=\"root\"></div>\n    // \t\t\t<script type=\"module\" src=\"http://127.0.0.1:5173/src/main.ts\"></script>\n    // \t\t</body>\n    // \t</html>\n    // `;\n    return `\n\t\t\t\t<!doctype html>\n\t\t\t\t<html lang=\"en\">\n\t\t\t\t\t<head>\n\t\t\t\t\t\t<script type=\"module\">import { injectIntoGlobalHook } from \"http://127.0.0.1:5173/@react-refresh\";\n\t\t\t\t\t\tinjectIntoGlobalHook(window);\n\t\t\t\t\t\twindow.$RefreshReg$ = () => {};\n\t\t\t\t\t\twindow.$RefreshSig$ = () => (type) => type;</script>\n\n\t\t\t\t\t\t<script type=\"module\" src=\"http://127.0.0.1:5173/@vite/client\"></script>\n\t\t\t\t\t\t<script>\n\t\t\t\t\t\t\twindow.vscode = acquireVsCodeApi();\n\t\t\t\t\t\t</script>\n\t\t\t\t\t\t<meta charset=\"UTF-8\" />\n\t\t\t\t\t\t<link rel=\"icon\" type=\"image/svg+xml\" href=\"http://127.0.0.1:5173/vite.svg\" />\n\t\t\t\t\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n\t\t\t\t\t\t<title>Vite + React + TS</title>\n\t\t\t\t\t</head>\n\t\t\t\t\t<body>\n\t\t\t\t\t\t<div id=\"root\"></div>\n\t\t\t\t\t\t<script type=\"module\" src=\"http://127.0.0.1:5173/src/main.tsx\"></script>\n\t\t\t\t\t</body>\n\t\t\t\t</html>\n\t\t`;\n  }\n  return `\n\t\t\t<!DOCTYPE html>\n\t\t\t<html>\n\t\t\t<head>\n\t\t\t\t<meta charset=\"utf-8\" />\n\t\t\t\t<meta\n\t\t\t\t\tname=\"viewport\"\n\t\t\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no\"\n\t\t\t\t/>\n\t\t\t\t<script>\n\t\t\t\t   window.vscode = acquireVsCodeApi();\n        </script>\n\t\t\t\t<script type=\"module\" crossorigin src=\"http://lowcode-utools.oss-cn-beijing.aliyuncs.com/vscode.index.js\"></script>\n\t\t\t\t<link rel=\"stylesheet\" crossorigin href=\"http://lowcode-utools.oss-cn-beijing.aliyuncs.com/vscode.index.css\">\n\t\t\t</head>\n\t\t\t<body>\n\t\t\t\t<div id=\"root\"></div>\n\t\t\t</body>\n\t\t</html>\n`;\n};\n"
  },
  {
    "path": "materials/snippets/打开webview/script/src/routes.ts",
    "content": "import * as controller from './controller';\n\nexport const routes: Record<string, any> = {\n  getMaterialPath: controller.getMaterialPath,\n  askGemini: controller.askGemini,\n  askChatGPT: controller.askChatGPT,\n};\n"
  },
  {
    "path": "materials/snippets/根据 DevOps 需求标题创建 GIT commit - 截图/config/preview.json",
    "content": "{\n\t\"title\": \"\",\n\t\"description\": \"\",\n\t\"img\": [\n\t\t\"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n\t],\n\t\"category\": [],\n\t\"notShowInCommand\": true,\n\t\"notShowInSnippetsList\": true,\n\t\"notShowInintellisense\": true,\n\t\"showInRunSnippetScript\": true,\n\t\"showInRunSnippetScriptOnExplorer\": false,\n\t\"runActivate\": false,\n\t\"schema\": \"amis\",\n\t\"scripts\": []\n}"
  },
  {
    "path": "materials/snippets/根据 DevOps 需求标题创建 GIT commit - 截图/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/根据 DevOps 需求标题创建 GIT commit - 截图/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/根据 DevOps 需求标题创建 GIT commit - 截图/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: (lowcodeContext) => {},\n  onSelect: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    await main.bootstrap();\n  },\n};\n"
  },
  {
    "path": "materials/snippets/根据 DevOps 需求标题创建 GIT commit - 截图/script/src/context.ts",
    "content": "import { CompileContext } from 'lowcode-context';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n} = {\n  lowcodeContext: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/根据 DevOps 需求标题创建 GIT commit - 截图/script/src/main.ts",
    "content": "import { window, env } from 'vscode';\nimport { generalBasic } from '@share/BaiduOCR';\nimport { getClipboardImage } from '@share/utils/clipboardImage';\nimport { context } from './context';\n\nexport async function bootstrap() {\n  const { lowcodeContext } = context;\n  const clipboardImage = await getClipboardImage(\n    lowcodeContext?.env.privateMaterialsPath || '',\n  ).catch((ex) => {\n    window.showErrorMessage(ex);\n  });\n  if (!clipboardImage) {\n    window.showErrorMessage('剪贴板里没有截图');\n  }\n  const ocrRes = await generalBasic({ image: clipboardImage! });\n  if (ocrRes.words_result.length > 1) {\n    const task = ocrRes.words_result[0].words.trim();\n    const title = ocrRes.words_result[1].words.trimStart();\n    window.showInformationMessage(\n      `内容已复制到剪贴板：feat(T${task}): #${task}/${title}`,\n    );\n    env.clipboard.writeText(`feat(T${task}): #${task}/${title}`);\n  } else {\n    const result = ocrRes.words_result[0]?.words.trimStart() || '';\n    const match = result.match(/^(\\d+)(.*)/);\n    if (match) {\n      const task = match[1]; // 开头的数字部分\n      const title = match[2]; // 其余的内容\n      window.showInformationMessage(\n        `内容已复制到剪贴板：feat(T${task}): #${task}/${title}`,\n      );\n      env.clipboard.writeText(`feat(T${task}): #${task}/${title}`);\n    } else {\n      window.showInformationMessage(\n        `数据异常：${JSON.stringify(ocrRes, null, 2)}`,\n      );\n    }\n  }\n}\n"
  },
  {
    "path": "materials/snippets/根据 DevOps 需求标题创建 GIT 分支名 - 截图 - TypeCheck/config/preview.json",
    "content": "{\n\t\"title\": \"\",\n\t\"description\": \"\",\n\t\"img\": [\n\t\t\"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n\t],\n\t\"category\": [],\n\t\"notShowInCommand\": true,\n\t\"notShowInSnippetsList\": true,\n\t\"notShowInintellisense\": true,\n\t\"showInRunSnippetScript\": true,\n\t\"showInRunSnippetScriptOnExplorer\": false,\n\t\"runActivate\": false,\n\t\"schema\": \"amis\",\n\t\"scripts\": []\n}"
  },
  {
    "path": "materials/snippets/根据 DevOps 需求标题创建 GIT 分支名 - 截图 - TypeCheck/config/schema.ts",
    "content": "export type TaskInfo = {\n  // 需求 id，用户发送内容的开头数字部分\n  taskId: string;\n  // 需求标题，用户发送内容去掉开头数字部分，请翻译成英文，不要直接翻译，要自然、流畅和地道，这部分内容会作为 git 分支名，请用中划线代替翻译后的空格\n  taskTitle: string;\n};\n"
  },
  {
    "path": "materials/snippets/根据 DevOps 需求标题创建 GIT 分支名 - 截图 - TypeCheck/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/根据 DevOps 需求标题创建 GIT 分支名 - 截图 - TypeCheck/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/根据 DevOps 需求标题创建 GIT 分支名 - 截图 - TypeCheck/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: (lowcodeContext) => {},\n  onSelect: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    await main.bootstrap();\n  },\n};\n"
  },
  {
    "path": "materials/snippets/根据 DevOps 需求标题创建 GIT 分支名 - 截图 - TypeCheck/script/src/context.ts",
    "content": "import { CompileContext } from 'lowcode-context';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n} = {\n  lowcodeContext: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/根据 DevOps 需求标题创建 GIT 分支名 - 截图 - TypeCheck/script/src/main.ts",
    "content": "import path from 'path';\nimport { window, env } from 'vscode';\nimport * as fs from 'fs-extra';\nimport { generalBasic } from '@share/BaiduOCR';\nimport { validate } from '@share/TypeChatSlim';\nimport { getClipboardImage } from '@share/utils/clipboardImage';\nimport { context } from './context';\n\nexport async function bootstrap() {\n  const { lowcodeContext } = context;\n  const clipboardImage = await getClipboardImage(\n    lowcodeContext?.env.privateMaterialsPath || '',\n  ).catch((ex) => {\n    window.showErrorMessage(ex);\n  });\n  if (!clipboardImage) {\n    window.showErrorMessage('剪贴板里没有截图');\n  }\n  const ocrRes = await generalBasic({ image: clipboardImage! });\n  const words = ocrRes.words_result.map((s) => s.words).join(' ');\n  const schema = fs.readFileSync(\n    path.join(lowcodeContext!.materialPath, 'config/schema.ts'),\n    'utf8',\n  );\n  const typeName = 'TaskInfo';\n  const requestPrompt = `\nYou are a service that translates user requests into JSON objects of type \"${typeName}\" according to the following TypeScript definitions:\n\\`\\`\\`ts\n${schema}\n\\`\\`\\`\nThe following is a user request:\n\\`\\`\\`\n${words}\n\\`\\`\\`\nThe following is the user request translated into a JSON object with 2 spaces of indentation and no properties with the value undefined:\n`;\n  const content = await context.lowcodeContext!.createChatCompletion({\n    messages: [\n      {\n        role: 'user',\n        content: requestPrompt,\n      },\n    ],\n    showWebview: true,\n    handleChunk: (chunck) => {},\n  });\n  const valid = validate<{ taskId: string; taskTitle: string }>(\n    content,\n    schema,\n    typeName,\n  );\n  if (valid.success) {\n    const branchName = `feat/T${valid.data.taskId}_${valid.data.taskTitle}`;\n    env.clipboard.writeText(branchName);\n    window.showInformationMessage(`分支名已复制到剪贴板：${branchName}`);\n  } else {\n    window.showErrorMessage(`JSON 校验失败：${valid.message}`);\n  }\n}\n"
  },
  {
    "path": "materials/snippets/根据JSON生成API请求方法/config/commandPrompt.ejs",
    "content": "<%- rawClipboardText %> \n根据这段 json 生成 ts 类型，名字为 I<%= rawSelectedText.slice(0, 1).toUpperCase() + rawSelectedText.slice(1) %>Result\n和下面的代码一起返回\nexport interface I<%= rawSelectedText.slice(0, 1).toUpperCase() + rawSelectedText.slice(1) %>Params {\n\tid: number;\n}\nexport interface I<%= rawSelectedText.slice(0, 1).toUpperCase() + rawSelectedText.slice(1) %>Data {\n\txx: string;\n}\nexport function <%= rawSelectedText %>(\n\tparams: I<%= rawSelectedText.slice(0, 1).toUpperCase() + rawSelectedText.slice(1) %>Params,\n\tdata: I<%= rawSelectedText.slice(0, 1).toUpperCase() + rawSelectedText.slice(1) %>Data,\n) {\n\treturn request<I<%= rawSelectedText.slice(0, 1).toUpperCase() + rawSelectedText.slice(1) %>Result>({\n\t\turl: `xxxx`,\n\t\tmethod: 'GET',\n\t\tparams,\n\t\tdata,\n\t});\n}\n返回 markdown 代码块"
  },
  {
    "path": "materials/snippets/根据JSON生成API请求方法/config/model.json",
    "content": "{}"
  },
  {
    "path": "materials/snippets/根据JSON生成API请求方法/config/preview.json",
    "content": "{\n\t\"title\": \"根据JSON生成API请求方法\",\n\t\"description\": \"根据JSON生成API请求方法\",\n\t\"img\": \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n}"
  },
  {
    "path": "materials/snippets/根据JSON生成API请求方法/config/schema.json",
    "content": "{}"
  },
  {
    "path": "materials/snippets/根据JSON生成API请求方法/src/template.ejs",
    "content": "<%- type %>\n\nexport interface I<%= rawSelectedText.slice(0, 1).toUpperCase() + rawSelectedText.slice(1) %>Params {\n  id: number;\n}\n  \nexport interface I<%= rawSelectedText.slice(0, 1).toUpperCase() + rawSelectedText.slice(1) %>Data {\n\txx: string;\n}\n  \nexport function <%= rawSelectedText %>(\n  params: I<%= rawSelectedText.slice(0, 1).toUpperCase() + rawSelectedText.slice(1) %>Params,\n  data: I<%= rawSelectedText.slice(0, 1).toUpperCase() + rawSelectedText.slice(1) %>Data,\n) {\n  return request<I<%= rawSelectedText.slice(0, 1).toUpperCase() + rawSelectedText.slice(1) %>Result>({\n    url: `xxxx`,\n    method: 'GET',\n    params,\n    data,\n  });\n}"
  },
  {
    "path": "materials/snippets/根据JSON生成MOCK方法/config/commandPrompt.ejs",
    "content": "<%- rawClipboardText %> \n生成一个 js 方法，方法名为 <%= rawSelectedText || 'getRandomData' %>，\n方法内部使用 mock.js 生成跟上面的 json 一样字段的数据，如果有数组则生成10个元素，\n最终的数据使用 Promise.resolve 返回\n返回markdown代码块"
  },
  {
    "path": "materials/snippets/根据JSON生成MOCK方法/config/model.json",
    "content": "{}"
  },
  {
    "path": "materials/snippets/根据JSON生成MOCK方法/config/preview.json",
    "content": "{\n\t\"title\": \"根据JSON生成MOCK方法\",\n\t\"description\": \"根据JSON生成MOCK方法\",\n\t\"img\": \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n}"
  },
  {
    "path": "materials/snippets/根据JSON生成MOCK方法/config/schema.json",
    "content": "{}"
  },
  {
    "path": "materials/snippets/根据JSON生成MOCK方法/src/template.ejs",
    "content": "const Mock = require('mockjs');\nconst { Random } = Mock;\n\nexport function <%= rawSelectedText || 'getRandomData' %>() {\n\t<%- mockCode %>\n  const res = <%- mockData %>\n\treturn Promise.resolve(res);\n}"
  },
  {
    "path": "materials/snippets/根据JSON生成TS类型/config/commandPrompt.ejs",
    "content": "<%- rawClipboardText %> \n根据这段 json 生成 ts 类型，名字为 <%= rawSelectedText || 'IResult' %>\n返回markdown代码块"
  },
  {
    "path": "materials/snippets/根据JSON生成TS类型/config/model.json",
    "content": "{}"
  },
  {
    "path": "materials/snippets/根据JSON生成TS类型/config/preview.json",
    "content": "{\n\t\"title\": \"根据JSON生成TS类型\",\n\t\"description\": \"根据JSON生成TS类型\",\n\t\"img\": \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n}"
  },
  {
    "path": "materials/snippets/根据JSON生成TS类型/config/schema.json",
    "content": "{}"
  },
  {
    "path": "materials/snippets/根据JSON生成TS类型/src/template.ejs",
    "content": "<%- type %>"
  },
  {
    "path": "materials/snippets/根据JSON生成TS类型-去除接口名称/config/commandPrompt.ejs",
    "content": "<%- rawClipboardText %> \n根据这段 json 生成 ts 类型，把类型名称去掉\n返回markdown代码块"
  },
  {
    "path": "materials/snippets/根据JSON生成TS类型-去除接口名称/config/model.json",
    "content": "{}"
  },
  {
    "path": "materials/snippets/根据JSON生成TS类型-去除接口名称/config/preview.json",
    "content": "{\n\t\"title\": \"根据JSON生成TS类型-去除接口名称\",\n\t\"description\": \"根据JSON生成TS类型-去除接口名称\",\n\t\"img\": \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n}"
  },
  {
    "path": "materials/snippets/根据JSON生成TS类型-去除接口名称/config/schema.json",
    "content": "{}"
  },
  {
    "path": "materials/snippets/根据JSON生成TS类型-去除接口名称/src/template.ejs",
    "content": "<%- type.replace(\"export interface IFetchResult\",\"\") %>"
  },
  {
    "path": "materials/snippets/根据JSON生成TS类型-将中文字段翻译成英文/config/commandPrompt.ejs",
    "content": "下面我让你来充当翻译家，你的目标是把中文翻译成英文单词，请翻译时使用驼峰格式，小写字母开头，不要带翻译腔，而是要翻译得自然、流畅和地道，使用优美和高雅的表达方式。请翻译下面的内容：“<%- rawSelectedText || rawClipboardText %>”"
  },
  {
    "path": "materials/snippets/根据JSON生成TS类型-将中文字段翻译成英文/config/model.json",
    "content": "{\n  \"name\": \"lowcode\"\n}"
  },
  {
    "path": "materials/snippets/根据JSON生成TS类型-将中文字段翻译成英文/config/preview.json",
    "content": "{\n  \"title\": \"\",\n  \"description\": \"\",\n  \"img\": [\n    \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n  ],\n  \"category\": [],\n  \"notShowInCommand\": true,\n  \"notShowInSnippetsList\": true,\n  \"notShowInintellisense\": true,\n  \"showInRunSnippetScript\": true,\n  \"schema\": \"amis\",\n  \"scripts\": []\n}"
  },
  {
    "path": "materials/snippets/根据JSON生成TS类型-将中文字段翻译成英文/config/schema.json",
    "content": "{\n  \"formSchema\": {\n    \"schema\": {\n      \"type\": \"page\",\n      \"body\": [\n        {\n          \"type\": \"form\",\n          \"title\": \"\",\n          \"body\": [\n            {\n              \"type\": \"input-text\",\n              \"name\": \"name\",\n              \"label\": \"测试表单\",\n              \"id\": \"u:4886baa626cf\",\n              \"value\": \"\"\n            }\n          ],\n          \"id\": \"u:67967afb0e69\",\n          \"submitText\": \"\"\n        }\n      ],\n      \"id\": \"u:d87dbf6bf8df\",\n      \"asideResizor\": false,\n      \"style\": {\n        \"boxShadow\": \" 0px 0px 0px 0px transparent\"\n      },\n      \"pullRefresh\": {\n        \"disabled\": true\n      },\n      \"regions\": [\n        \"body\"\n      ]\n    }\n  }\n}"
  },
  {
    "path": "materials/snippets/根据JSON生成TS类型-将中文字段翻译成英文/config/viewPrompt.ejs",
    "content": ""
  },
  {
    "path": "materials/snippets/根据JSON生成TS类型-将中文字段翻译成英文/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/根据JSON生成TS类型-将中文字段翻译成英文/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/根据JSON生成TS类型-将中文字段翻译成英文/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: (lowcodeContext) => {},\n  onSelect: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    await main.bootstrap();\n  },\n};\n"
  },
  {
    "path": "materials/snippets/根据JSON生成TS类型-将中文字段翻译成英文/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { ViewCallContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: ViewCallContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/根据JSON生成TS类型-将中文字段翻译成英文/script/src/main.ts",
    "content": "import { env, window, Range } from 'vscode';\nimport { context } from './context';\n\nexport async function bootstrap() {\n  const clipboardText = await env.clipboard.readText();\n  const { selection, document } = window.activeTextEditor!;\n  const selectText = document.getText(selection).trim();\n  let content = await context.lowcodeContext!.createChatCompletion({\n    messages: [\n      {\n        role: 'system',\n        content: `你是一个代码专家，你的目标是把 JSON 数据转换成 TypeScript 类型，严格按照以下要求进行处理：类型名称根据每个字段意思推测出来；类型声明使用 type 关键字；把中文字段翻译成英文；将原来的中文作为字段的注释，注释是中文，而且注释使用 jsdoc 的格式；请翻译时使用驼峰格式，小写字母开头，不要带翻译腔，而是要翻译得自然、流畅和地道，使用优美和高雅的表达方式。请处理下面用户输入的内容`,\n      },\n      {\n        role: 'user',\n        content: selectText || clipboardText,\n      },\n    ],\n  });\n  content = content.replace('```typescript', '').replace('```', '');\n  window.activeTextEditor?.edit((editBuilder) => {\n    if (window.activeTextEditor?.selection.isEmpty) {\n      editBuilder.insert(window.activeTextEditor.selection.start, content);\n    } else {\n      editBuilder.replace(\n        new Range(\n          window.activeTextEditor!.selection.start,\n          window.activeTextEditor!.selection.end,\n        ),\n        content,\n      );\n    }\n  });\n}\n"
  },
  {
    "path": "materials/snippets/根据JSON生成TS类型-将中文字段翻译成英文/src/template.ejs",
    "content": "<%= name %>"
  },
  {
    "path": "materials/snippets/根据TS类型生成API请求方法/config/model.json",
    "content": "{}"
  },
  {
    "path": "materials/snippets/根据TS类型生成API请求方法/config/preview.json",
    "content": "{\n\t\"title\": \"\",\n\t\"description\": \"\",\n\t\"img\": \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\",\n\t\"category\": []\n}"
  },
  {
    "path": "materials/snippets/根据TS类型生成API请求方法/config/schema.json",
    "content": "{}"
  },
  {
    "path": "materials/snippets/根据TS类型生成API请求方法/src/template.ejs",
    "content": "export interface I<%= rawSelectedText.slice(0, 1).toUpperCase() + rawSelectedText.slice(1) %>Result {\n\tcode: number;\n\tmsg: string;\n\tresult: <%- rawClipboardText %>\n}\n\nexport interface I<%= rawSelectedText.slice(0, 1).toUpperCase() + rawSelectedText.slice(1) %>Params {\n\tid: number;\n}\n  \nexport interface I<%= rawSelectedText.slice(0, 1).toUpperCase() + rawSelectedText.slice(1) %>Data {\n\txx: string;\n}\n  \nexport function <%= rawSelectedText %>(\n\tparams: I<%= rawSelectedText.slice(0, 1).toUpperCase() + rawSelectedText.slice(1) %>Params,\n\tdata: I<%= rawSelectedText.slice(0, 1).toUpperCase() + rawSelectedText.slice(1) %>Data,\n) {\n\treturn request<I<%= rawSelectedText.slice(0, 1).toUpperCase() + rawSelectedText.slice(1) %>Result>({\n\t\turl: `xxxx`,\n\t\tmethod: 'GET',\n\t\tparams,\n\t\tdata,\n\t});\n}"
  },
  {
    "path": "materials/snippets/根据TS类型生成MOCK方法/config/commandPrompt.ejs",
    "content": "<%- rawClipboardText %> \n生成一个 js 方法，方法名为 <%= rawSelectedText || 'getRandomData' %>，\n方法内部使用 mock.js 生成跟上面的 ts 类型一样字段的数据，如果有数组则生成10个元素，\n最终的数据使用 Promise.resolve 返回\n返回markdown代码块"
  },
  {
    "path": "materials/snippets/根据TS类型生成MOCK方法/config/model.json",
    "content": "{}"
  },
  {
    "path": "materials/snippets/根据TS类型生成MOCK方法/config/preview.json",
    "content": "{\n\t\"title\": \"根据TS类型生成MOCK方法\",\n\t\"description\": \"根据TS类型生成MOCK方法\",\n\t\"img\": \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n}"
  },
  {
    "path": "materials/snippets/根据TS类型生成MOCK方法/config/schema.json",
    "content": "{}"
  },
  {
    "path": "materials/snippets/根据TS类型生成MOCK方法/src/template.ejs",
    "content": "const Mock = require('mockjs');\nconst { Random } = Mock;\n\nexport function <%= rawSelectedText || 'getRandomData' %>() {\n\t<%- mockCode %>\n  const res = <%- mockData %>\n\treturn Promise.resolve(res);\n}"
  },
  {
    "path": "materials/snippets/根据TS类型生成markdown表格/config/commandPrompt.ejs",
    "content": "<%- rawSelectedText || rawClipboardText %>\n根据 ts 类型生成 markdown table，\n格式如：|参数|说明|类型|必须|，\n其中参数为类型字段名称，\n说明为字段注释，\n类型为字段类型，\n必须为字段是否为 required。\n返回 markdown"
  },
  {
    "path": "materials/snippets/根据TS类型生成markdown表格/config/model.json",
    "content": "{\n  \"name\": \"lowcode\"\n}"
  },
  {
    "path": "materials/snippets/根据TS类型生成markdown表格/config/preview.json",
    "content": "{\n\t\"title\": \"\",\n\t\"description\": \"\",\n\t\"img\": [\n\t\t\"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n\t],\n\t\"category\": [],\n\t\"notShowInCommand\": true,\n\t\"notShowInSnippetsList\": true,\n\t\"notShowInintellisense\": true,\n\t\"schema\": \"amis\"\n}"
  },
  {
    "path": "materials/snippets/根据TS类型生成markdown表格/config/schema.json",
    "content": "{\n  \"formSchema\": {\n    \"schema\": {\n      \"type\": \"page\",\n      \"body\": [\n        {\n          \"type\": \"form\",\n          \"title\": \"\",\n          \"body\": [\n            {\n              \"type\": \"input-text\",\n              \"name\": \"name\",\n              \"label\": \"测试表单\",\n              \"id\": \"u:4886baa626cf\",\n              \"value\": \"\"\n            }\n          ],\n          \"id\": \"u:67967afb0e69\",\n          \"submitText\": \"\"\n        }\n      ],\n      \"id\": \"u:d87dbf6bf8df\",\n      \"asideResizor\": false,\n      \"style\": {\n        \"boxShadow\": \" 0px 0px 0px 0px transparent\"\n      },\n      \"pullRefresh\": {\n        \"disabled\": true\n      },\n      \"regions\": [\n        \"body\"\n      ]\n    }\n  }\n}"
  },
  {
    "path": "materials/snippets/根据TS类型生成markdown表格/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/根据TS类型生成markdown表格/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/根据TS类型生成markdown表格/script/src/context');\n\nmodule.exports = {\n  beforeCompile: () => {},\n  afterCompile: () => {\n    context.outputChannel.appendLine('compile 根据TS类型生成markdown表格 end');\n  },\n};\n"
  },
  {
    "path": "materials/snippets/根据TS类型生成markdown表格/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { CompileContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/根据TS类型生成markdown表格/script/src/main.ts",
    "content": "export const main = 1;\n"
  },
  {
    "path": "materials/snippets/根据TS类型生成markdown表格/src/template.ejs",
    "content": "<%= name %>"
  },
  {
    "path": "materials/snippets/根据YAPI接口定义生成高级Mock脚本/config/model.json",
    "content": "{}"
  },
  {
    "path": "materials/snippets/根据YAPI接口定义生成高级Mock脚本/config/preview.json",
    "content": "{\n\t\"title\": \"\",\n\t\"description\": \"\",\n\t\"img\": \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\",\n\t\"category\": [\n\t\t\"YAPI\",\n\t\t\"脚本\"\n\t]\n}"
  },
  {
    "path": "materials/snippets/根据YAPI接口定义生成高级Mock脚本/config/schema.json",
    "content": "{}"
  },
  {
    "path": "materials/snippets/根据YAPI接口定义生成高级Mock脚本/src/template.ejs",
    "content": "<%- mockCode %>\nconst mockData = <%- mockData %>\n\nObject.assign( mockJson, mockData)\n"
  },
  {
    "path": "materials/snippets/测试 JSONSchemaChat/config/commandPrompt.ejs",
    "content": "<%- rawSelectedText || rawClipboardText %>\n解释这段代码的意思"
  },
  {
    "path": "materials/snippets/测试 JSONSchemaChat/config/model.json",
    "content": "{\n\t\"filters\": [\n\t\t{\n\t\t\t\"component\": \"select\",\n\t\t\t\"key\": \"店铺名称\",\n\t\t\t\"label\": \"店铺名称\",\n\t\t\t\"placeholder\": \"请输入\"\n\t\t},\n\t\t{\n\t\t\t\"component\": \"select\",\n\t\t\t\"key\": \"店铺编码\",\n\t\t\t\"label\": \"店铺编码\",\n\t\t\t\"placeholder\": \"请输入\"\n\t\t},\n\t\t{\n\t\t\t\"component\": \"select\",\n\t\t\t\"key\": \"店铺门头编码\",\n\t\t\t\"label\": \"店铺门头编码\",\n\t\t\t\"placeholder\": \"请输入\"\n\t\t},\n\t\t{\n\t\t\t\"component\": \"select\",\n\t\t\t\"key\": \"所在区域\",\n\t\t\t\"label\": \"所在区域\",\n\t\t\t\"placeholder\": \"全部\"\n\t\t}\n\t],\n\t\"columns\": [\n\t\t{\n\t\t\t\"slot\": false,\n\t\t\t\"title\": \"店铺编码\",\n\t\t\t\"dataIndex\": \"店铺编码\",\n\t\t\t\"key\": \"店铺编码\"\n\t\t},\n\t\t{\n\t\t\t\"slot\": false,\n\t\t\t\"title\": \"店铺名称\",\n\t\t\t\"dataIndex\": \"店铺名称\",\n\t\t\t\"key\": \"店铺名称\"\n\t\t},\n\t\t{\n\t\t\t\"slot\": false,\n\t\t\t\"title\": \"店铺业务范围\",\n\t\t\t\"dataIndex\": \"店铺业务范围\",\n\t\t\t\"key\": \"店铺业务范围\"\n\t\t},\n\t\t{\n\t\t\t\"slot\": false,\n\t\t\t\"title\": \"店铺类型\",\n\t\t\t\"dataIndex\": \"店铺类型\",\n\t\t\t\"key\": \"店铺类型\"\n\t\t},\n\t\t{\n\t\t\t\"slot\": false,\n\t\t\t\"title\": \"所在区域\",\n\t\t\t\"dataIndex\": \"所在区域\",\n\t\t\t\"key\": \"所在区域\"\n\t\t},\n\t\t{\n\t\t\t\"slot\": false,\n\t\t\t\"title\": \"详细地址\",\n\t\t\t\"dataIndex\": \"详细地址\",\n\t\t\t\"key\": \"详细地址\"\n\t\t}\n\t],\n\t\"pagination\": {\n\t\t\"show\": true,\n\t\t\"page\": \"page\",\n\t\t\"size\": \"size\",\n\t\t\"total\": \"result.total\"\n\t},\n\t\"includeModifyModal\": false,\n\t\"fetchName\": \"fetchTableList\",\n\t\"result\": \"[\\\"result\\\"][\\\"records\\\"]\",\n\t\"serviceName\": \"getTableList\"\n}"
  },
  {
    "path": "materials/snippets/测试 JSONSchemaChat/config/preview.json",
    "content": "{\n\t\"title\": \"\",\n\t\"description\": \"\",\n\t\"img\": [\n\t\t\"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n\t],\n\t\"category\": [],\n\t\"notShowInCommand\": true,\n\t\"notShowInSnippetsList\": true,\n\t\"notShowInintellisense\": true,\n\t\"showInRunSnippetScript\": true,\n\t\"schema\": \"amis\",\n\t\"scripts\": []\n}"
  },
  {
    "path": "materials/snippets/测试 JSONSchemaChat/config/schema.json",
    "content": "{\n  \"formSchema\": {\n    \"schema\": {\n      \"type\": \"page\",\n      \"body\": [],\n      \"id\": \"u:d87dbf6bf8df\",\n      \"asideResizor\": false,\n      \"style\": {\n        \"boxShadow\": \" 0px 0px 0px 0px transparent\"\n      },\n      \"pullRefresh\": {\n        \"disabled\": true\n      },\n      \"regions\": [\n        \"body\"\n      ]\n    }\n  }\n}"
  },
  {
    "path": "materials/snippets/测试 JSONSchemaChat/config/validSchema.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n  \"title\": \"\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"filters\": {\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"component\": {\n            \"type\": \"string\"\n          },\n          \"key\": {\n            \"type\": \"string\",\n            \"description\": \"翻译成英文，驼峰格式\"\n          },\n          \"label\": {\n            \"type\": \"string\",\n            \"description\": \"保持原始内容，不要翻译\"\n          },\n          \"placeholder\": {\n            \"type\": \"string\",\n            \"description\": \"保持原始内容，不要翻译\"\n          }\n        },\n        \"required\": [\n          \"component\",\n          \"key\",\n          \"label\",\n          \"placeholder\"\n        ]\n      }\n    },\n    \"columns\": {\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"slot\": {\n            \"type\": \"boolean\"\n          },\n          \"title\": {\n            \"type\": \"string\",\n            \"description\": \"保持原始内容，不要翻译\"\n          },\n          \"dataIndex\": {\n            \"type\": \"string\",\n            \"description\": \"翻译成英文，驼峰格式\"\n          },\n          \"key\": {\n            \"type\": \"string\",\n            \"description\": \"翻译成英文，驼峰格式\"\n          }\n        },\n        \"required\": [\n          \"slot\",\n          \"title\",\n          \"dataIndex\",\n          \"key\"\n        ]\n      }\n    },\n    \"pagination\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"show\": {\n          \"type\": \"boolean\"\n        },\n        \"page\": {\n          \"type\": \"string\"\n        },\n        \"size\": {\n          \"type\": \"string\"\n        },\n        \"total\": {\n          \"type\": \"string\"\n        }\n      },\n      \"required\": [\n        \"show\",\n        \"page\",\n        \"size\",\n        \"total\"\n      ]\n    },\n    \"includeModifyModal\": {\n      \"type\": \"boolean\"\n    },\n    \"fetchName\": {\n      \"type\": \"string\"\n    },\n    \"result\": {\n      \"type\": \"string\"\n    },\n    \"serviceName\": {\n      \"type\": \"string\"\n    }\n  },\n  \"required\": [\n    \"filters\",\n    \"columns\",\n    \"pagination\",\n    \"includeModifyModal\",\n    \"fetchName\",\n    \"result\",\n    \"serviceName\"\n  ]\n}"
  },
  {
    "path": "materials/snippets/测试 JSONSchemaChat/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/测试 JSONSchemaChat/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/测试 JSONSchemaChat/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: (lowcodeContext) => {},\n  onSelect: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    await main.bootstrap();\n  },\n};\n"
  },
  {
    "path": "materials/snippets/测试 JSONSchemaChat/script/src/context.ts",
    "content": "import { ViewCallContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: ViewCallContext;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/测试 JSONSchemaChat/script/src/main.ts",
    "content": "import fs from 'fs';\nimport path from 'path';\nimport { env, window, Range } from 'vscode';\nimport { translate } from '@share/JSONSchemaChat/index';\nimport { context } from './context';\n\nexport async function bootstrap() {\n  const { lowcodeContext } = context;\n  const schema = fs.readFileSync(\n    path.join(lowcodeContext!.materialPath, 'config/validSchema.json'),\n    'utf8',\n  );\n  const clipboardText = await env.clipboard.readText();\n  const { selection, document } = window.activeTextEditor!;\n  const selectText = document.getText(selection).trim();\n  const res = await translate({\n    schema,\n    request: selectText || clipboardText,\n    createChatCompletion: lowcodeContext!.createChatCompletion,\n    showWebview: true,\n  });\n  if (res.success) {\n    window.activeTextEditor?.edit((editBuilder) => {\n      // editBuilder.replace(activeTextEditor.selection, content);\n      if (window.activeTextEditor?.selection.isEmpty) {\n        editBuilder.insert(\n          window.activeTextEditor.selection.start,\n          JSON.stringify(res.data),\n        );\n      } else {\n        editBuilder.replace(\n          new Range(\n            window.activeTextEditor!.selection.start,\n            window.activeTextEditor!.selection.end,\n          ),\n          JSON.stringify(res.data),\n        );\n      }\n    });\n  } else {\n    window.showErrorMessage(res.message);\n  }\n}\n"
  },
  {
    "path": "materials/snippets/测试 JSONSchemaChat/src/template.ejs",
    "content": "<%= name %>"
  },
  {
    "path": "materials/snippets/测试脚本/config/model.json",
    "content": "{}"
  },
  {
    "path": "materials/snippets/测试脚本/config/preview.json",
    "content": "{\n  \"title\": \"\",\n  \"description\": \"\",\n  \"img\": \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\",\n  \"showInRunSnippetScript\": true,\n  \"runActivate\": true\n}\n"
  },
  {
    "path": "materials/snippets/测试脚本/config/schema.json",
    "content": "{}"
  },
  {
    "path": "materials/snippets/测试脚本/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/测试脚本/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/测试脚本/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {\n    context.outputChannel.appendLine(Object.keys(lowcodeContext));\n    context.vscode.window.showErrorMessage('12134');\n    return { a: 'lowcode' };\n  },\n  afterCompile: (lowcodeContext) => {\n    context.outputChannel.appendLine(Object.keys(lowcodeContext));\n  },\n  onSelect: async (lowcodeContext) => {\n    await main.bootstrap();\n  },\n  onActivate: () => {\n    main.onActivate();\n  },\n};\n"
  },
  {
    "path": "materials/snippets/测试脚本/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { CompileContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/测试脚本/script/src/main.ts",
    "content": "import { window } from 'vscode';\n\nexport async function bootstrap() {\n  window.onDidChangeWindowState((state) => {\n    console.log(state.focused, 123);\n  });\n}\n\nexport function onActivate() {\n  // window.showInformationMessage('你好');\n}\n"
  },
  {
    "path": "materials/snippets/测试脚本/src/template.ejs",
    "content": "测试编译前后脚本"
  },
  {
    "path": "materials/snippets/生成 value-label 格式 JSON/config/commandPrompt.ejs",
    "content": "export const <%- rawSelectedText %>Options = <%- content %>\n\nexport const <%- rawSelectedText %>Map = <%- rawSelectedText %>Options.reduce((obj, { label, value }) => {\n  obj[value] = label\n  return obj\n}, {})\n"
  },
  {
    "path": "materials/snippets/生成 value-label 格式 JSON/config/model.json",
    "content": "{\n  \"name\": \"lowcode\"\n}"
  },
  {
    "path": "materials/snippets/生成 value-label 格式 JSON/config/preview.json",
    "content": "{\n\t\"title\": \"\",\n\t\"description\": \"\",\n\t\"img\": [\n\t\t\"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n\t],\n\t\"category\": [],\n\t\"notShowInCommand\": false,\n\t\"notShowInSnippetsList\": true,\n\t\"notShowInintellisense\": true,\n\t\"showInRunSnippetScript\": true,\n\t\"schema\": \"amis\",\n\t\"scripts\": []\n}"
  },
  {
    "path": "materials/snippets/生成 value-label 格式 JSON/config/schema.json",
    "content": "{\n  \"formSchema\": {\n    \"schema\": {\n      \"type\": \"page\",\n      \"body\": [\n        {\n          \"type\": \"form\",\n          \"title\": \"\",\n          \"body\": [\n            {\n              \"type\": \"input-text\",\n              \"name\": \"name\",\n              \"label\": \"测试表单\",\n              \"id\": \"u:4886baa626cf\",\n              \"value\": \"\"\n            }\n          ],\n          \"id\": \"u:67967afb0e69\",\n          \"submitText\": \"\"\n        }\n      ],\n      \"id\": \"u:d87dbf6bf8df\",\n      \"asideResizor\": false,\n      \"style\": {\n        \"boxShadow\": \" 0px 0px 0px 0px transparent\"\n      },\n      \"pullRefresh\": {\n        \"disabled\": true\n      },\n      \"regions\": [\n        \"body\"\n      ]\n    }\n  }\n}"
  },
  {
    "path": "materials/snippets/生成 value-label 格式 JSON/config/schema.ts",
    "content": "export type IOption = { value: string; label: string }[];\n"
  },
  {
    "path": "materials/snippets/生成 value-label 格式 JSON/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/生成 value-label 格式 JSON/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/生成 value-label 格式 JSON/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: (lowcodeContext) => {},\n  onSelect: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    await main.bootstrap();\n  },\n};\n"
  },
  {
    "path": "materials/snippets/生成 value-label 格式 JSON/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { ViewCallContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: ViewCallContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/生成 value-label 格式 JSON/script/src/main.ts",
    "content": "import fs from 'fs';\nimport path from 'path';\nimport { env, window, Range } from 'vscode';\nimport { translate } from '@share/TypeChatSlim/index';\nimport { getMaterial } from '@share/utils/material';\nimport { compile as compileEjs } from '@share/utils/ejs';\nimport { pasteToEditor } from '@share/utils/editor';\nimport { context } from './context';\n\nexport async function bootstrap() {\n  const { lowcodeContext } = context;\n  const schema = fs.readFileSync(\n    path.join(lowcodeContext!.materialPath, 'config/schema.ts'),\n    'utf8',\n  );\n  const clipboardText = await env.clipboard.readText();\n  const { selection, document } = window.activeTextEditor!;\n  const selectText = document.getText(selection).trim();\n  const template = getMaterial(lowcodeContext!.materialPath);\n  lowcodeContext?.outputChannel.appendLine(lowcodeContext!.materialPath);\n  const res = await translate({\n    schema,\n    typeName: 'IOption',\n    request: clipboardText,\n    createChatCompletion: lowcodeContext!.createChatCompletion,\n    showWebview: true,\n  });\n  if (res.success) {\n    const code = compileEjs(template!.commandPrompt, {\n      rawSelectedText: selectText,\n      content: JSON.stringify(res.data),\n    } as any);\n    window.activeTextEditor?.edit((editBuilder) => {\n      // editBuilder.replace(activeTextEditor.selection, content);\n      if (window.activeTextEditor?.selection.isEmpty) {\n        editBuilder.insert(window.activeTextEditor.selection.start, code);\n      } else {\n        editBuilder.replace(\n          new Range(\n            window.activeTextEditor!.selection.start,\n            window.activeTextEditor!.selection.end,\n          ),\n          code,\n        );\n      }\n    });\n  } else {\n    window.showErrorMessage(res.message);\n  }\n}\n"
  },
  {
    "path": "materials/snippets/生成 value-label 格式 JSON/src/template.ejs",
    "content": "<%= name %>"
  },
  {
    "path": "materials/snippets/翻译成驼峰格式/config/commandPrompt.ejs",
    "content": "下面我让你来充当翻译家，你的目标是把中文翻译成英文单词，请翻译时使用驼峰格式，小写字母开头，不要带翻译腔，而是要翻译得自然、流畅和地道，使用优美和高雅的表达方式。\n请翻译下面的内容：“<%- rawSelectedText || rawClipboardText %>”"
  },
  {
    "path": "materials/snippets/翻译成驼峰格式/config/model.json",
    "content": "{\n  \"name\": \"lowcode\"\n}"
  },
  {
    "path": "materials/snippets/翻译成驼峰格式/config/preview.json",
    "content": "{\n  \"title\": \"\",\n  \"description\": \"\",\n  \"img\": [\n    \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n  ],\n  \"category\": [],\n  \"notShowInCommand\": true,\n  \"notShowInSnippetsList\": true,\n  \"notShowInintellisense\": true,\n  \"showInRunSnippetScript\": true,\n  \"schema\": \"amis\",\n  \"scripts\": []\n}"
  },
  {
    "path": "materials/snippets/翻译成驼峰格式/config/schema.json",
    "content": "{\n  \"formSchema\": {\n    \"schema\": {\n      \"type\": \"page\",\n      \"body\": [\n        {\n          \"type\": \"form\",\n          \"title\": \"\",\n          \"body\": [\n            {\n              \"type\": \"input-text\",\n              \"name\": \"name\",\n              \"label\": \"测试表单\",\n              \"id\": \"u:4886baa626cf\",\n              \"value\": \"\"\n            }\n          ],\n          \"id\": \"u:67967afb0e69\",\n          \"submitText\": \"\"\n        }\n      ],\n      \"id\": \"u:d87dbf6bf8df\",\n      \"asideResizor\": false,\n      \"style\": {\n        \"boxShadow\": \" 0px 0px 0px 0px transparent\"\n      },\n      \"pullRefresh\": {\n        \"disabled\": true\n      },\n      \"regions\": [\n        \"body\"\n      ]\n    }\n  }\n}"
  },
  {
    "path": "materials/snippets/翻译成驼峰格式/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/翻译成驼峰格式/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/翻译成驼峰格式/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: (lowcodeContext) => {},\n  onSelect: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    await main.bootstrap();\n  },\n};\n"
  },
  {
    "path": "materials/snippets/翻译成驼峰格式/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { ViewCallContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: ViewCallContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/翻译成驼峰格式/script/src/main.ts",
    "content": "import { env, window, Range } from 'vscode';\nimport { context } from './context';\n\nexport async function bootstrap() {\n  const clipboardText = await env.clipboard.readText();\n  const { selection, document } = window.activeTextEditor!;\n  const selectText = document.getText(selection).trim();\n  let content = await context.lowcodeContext!.createChatCompletion({\n    messages: [\n      {\n        role: 'system',\n        content: `你是一个翻译家，你的目标是把中文翻译成英文单词，请翻译时使用驼峰格式，小写字母开头，不要带翻译腔，而是要翻译得自然、流畅和地道，使用优美和高雅的表达方式。请翻译下面用户输入的内容`,\n      },\n      {\n        role: 'user',\n        content: selectText || clipboardText,\n      },\n    ],\n  });\n  content = content.charAt(0).toLowerCase() + content.slice(1);\n  window.activeTextEditor?.edit((editBuilder) => {\n    if (window.activeTextEditor?.selection.isEmpty) {\n      editBuilder.insert(window.activeTextEditor.selection.start, content);\n    } else {\n      editBuilder.replace(\n        new Range(\n          window.activeTextEditor!.selection.start,\n          window.activeTextEditor!.selection.end,\n        ),\n        content,\n      );\n    }\n  });\n}\n"
  },
  {
    "path": "materials/snippets/翻译成驼峰格式/src/template.ejs",
    "content": "<%= name %>"
  },
  {
    "path": "materials/snippets/自动保存活动窗口/config/model.json",
    "content": "{}"
  },
  {
    "path": "materials/snippets/自动保存活动窗口/config/preview.json",
    "content": "{\n  \"title\": \"\",\n  \"description\": \"\",\n  \"img\": \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\",\n  \"showInRunSnippetScript\": false,\n  \"runActivate\": true\n}\n"
  },
  {
    "path": "materials/snippets/自动保存活动窗口/config/schema.json",
    "content": "{}"
  },
  {
    "path": "materials/snippets/自动保存活动窗口/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/自动保存活动窗口/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/自动保存活动窗口/script/src/context');\n\nmodule.exports = {\n  onActivate: (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    main.onActivate();\n  },\n};\n"
  },
  {
    "path": "materials/snippets/自动保存活动窗口/script/src/context.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { CompileContext } from 'lowcode-context';\nimport { StatusBarItem } from 'vscode';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n  nestApp?: INestApplication<any>;\n  statusBarItem?: StatusBarItem;\n} = {\n  lowcodeContext: undefined,\n  nestApp: undefined,\n  statusBarItem: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/自动保存活动窗口/script/src/main.ts",
    "content": "import { Uri, commands, env, window, workspace } from 'vscode';\nimport { saveShareData } from '@share/utils/shareData';\nimport { context } from './context';\n\nexport function onActivate() {\n  const { lowcodeContext } = context;\n  saveShareData({\n    activeWindow:\n      (workspace.workspaceFolders && workspace.workspaceFolders[0].uri.path) ||\n      '',\n  });\n  window.onDidChangeWindowState((state) => {\n    if (state.focused) {\n      saveShareData({\n        activeWindow:\n          (workspace.workspaceFolders &&\n            workspace.workspaceFolders[0].uri.path) ||\n          '',\n      });\n    }\n  });\n\n  // 获取选中的文件夹\n  commands.getCommands().then((res) => {\n    if (!res.some((s) => s.includes('lowcode.getSelectedFolder'))) {\n      const getSelectedFolder = commands.registerCommand(\n        'lowcode.getSelectedFolder',\n        async () => {\n          const oriClipboardText = await env.clipboard.readText();\n          await commands.executeCommand('copyFilePath');\n          const folder = await env.clipboard.readText();\n          env.clipboard.writeText(oriClipboardText);\n          const newUri = Uri.file(folder);\n          saveShareData({\n            selectedFolder:\n              process.platform === 'win32' && newUri.path.startsWith('/')\n                ? newUri.path.substring(1)\n                : newUri.path,\n          });\n          console.log(newUri.path);\n        },\n      );\n      lowcodeContext?.env.extensionContext.subscriptions.push(\n        getSelectedFolder,\n      );\n    }\n  });\n}\n"
  },
  {
    "path": "materials/snippets/获取当前用户最近一次 Git Commit 信息/config/preview.json",
    "content": "{\n\t\"title\": \"\",\n\t\"description\": \"\",\n\t\"img\": [\n\t\t\"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n\t],\n\t\"category\": [],\n\t\"notShowInCommand\": true,\n\t\"notShowInSnippetsList\": true,\n\t\"notShowInintellisense\": true,\n\t\"showInRunSnippetScript\": true,\n\t\"showInRunSnippetScriptOnExplorer\": false,\n\t\"runActivate\": false,\n\t\"schema\": \"amis\",\n\t\"scripts\": []\n}"
  },
  {
    "path": "materials/snippets/获取当前用户最近一次 Git Commit 信息/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/获取当前用户最近一次 Git Commit 信息/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/获取当前用户最近一次 Git Commit 信息/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: (lowcodeContext) => {},\n  onSelect: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    await main.bootstrap();\n  },\n};\n"
  },
  {
    "path": "materials/snippets/获取当前用户最近一次 Git Commit 信息/script/src/context.ts",
    "content": "import { CompileContext } from 'lowcode-context';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n} = {\n  lowcodeContext: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/获取当前用户最近一次 Git Commit 信息/script/src/main.ts",
    "content": "import { platform } from 'os';\nimport * as execa from 'execa';\nimport { window, env } from 'vscode';\nimport { getShareData } from '@share/utils/shareData';\n\nexport function bootstrap() {\n  const { activeWindow } = getShareData();\n  try {\n    const projectPath =\n      platform() === 'win32' && activeWindow?.startsWith('/')\n        ? activeWindow.substring(1)\n        : activeWindow;\n    const userName = execa.sync('git', [\n      '-C',\n      projectPath || '.',\n      'config',\n      'user.name',\n    ]);\n    const res = execa.sync('git', [\n      '-C',\n      projectPath || '.',\n      'log',\n      '-1',\n      '--pretty=format:%s',\n      `--author=${userName.stdout}`,\n      // 'log -1 --pretty=format:\"%s\" --author=\"$(git config user.name)\"',\n    ]);\n    if (res.stdout) {\n      env.clipboard.writeText(res.stdout);\n      window.showInformationMessage(`内容已复制到剪贴板：${res.stdout}`);\n      return;\n    }\n    window.showInformationMessage(`数据异常${JSON.stringify(res)}`);\n  } catch (ex) {\n    window.showInformationMessage(`数据异常${(ex as object).toString()}`);\n  }\n}\n"
  },
  {
    "path": "materials/snippets/设置配置信息/config/model.json",
    "content": "{}\n"
  },
  {
    "path": "materials/snippets/设置配置信息/config/preview.json",
    "content": "{\n  \"title\": \"\",\n  \"description\": \"\",\n  \"img\": [\n    \"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n  ],\n  \"category\": [],\n  \"notShowInCommand\": true,\n  \"notShowInSnippetsList\": true,\n  \"notShowInintellisense\": true,\n  \"showInRunSnippetScript\": true,\n  \"showInRunSnippetScriptOnExplorer\": false,\n  \"runActivate\": false,\n  \"schema\": \"amis\",\n  \"scripts\": [\n    {\n      \"method\": \"saveConfig\",\n      \"remark\": \"保存配置信息\"\n    }\n  ]\n}\n"
  },
  {
    "path": "materials/snippets/设置配置信息/config/schema.json",
    "content": "{\n  \"type\": \"page\",\n  \"name\": \"page\",\n  \"body\": [\n    {\n      \"type\": \"form\",\n      \"name\": \"form\",\n      \"data\": {},\n      \"title\": \"\",\n      \"body\": [\n        {\n          \"type\": \"input-text\",\n          \"id\": \"u:11b127c5df46\",\n          \"label\": \"activeWindow\",\n          \"name\": \"activeWindow\",\n          \"description\": \"\"\n        },\n        {\n          \"type\": \"combo\",\n          \"label\": \"oneAPI\",\n          \"name\": \"oneAPI\",\n          \"multiple\": true,\n          \"addable\": true,\n          \"removable\": true,\n          \"removableMode\": \"icon\",\n          \"addBtn\": {\n            \"label\": \"新增\",\n            \"icon\": \"fa fa-plus\",\n            \"level\": \"primary\",\n            \"size\": \"sm\",\n            \"id\": \"u:47ecb9e15ff1\"\n          },\n          \"items\": [\n            {\n              \"type\": \"input-text\",\n              \"label\": \"hostname\",\n              \"name\": \"hostname\",\n              \"id\": \"u:6496cac4f4b8\",\n              \"description\": \"\"\n            },\n            {\n              \"type\": \"input-text\",\n              \"label\": \"apiPath\",\n              \"name\": \"apiPath\",\n              \"id\": \"u:a701e97d81a6\",\n              \"description\": \"\"\n            },\n            {\n              \"type\": \"switch\",\n              \"label\": \"notHttps\",\n              \"option\": \"\",\n              \"name\": \"notHttps\",\n              \"falseValue\": false,\n              \"trueValue\": true,\n              \"id\": \"u:a3283c2ac1b6\",\n              \"value\": false\n            },\n            {\n              \"type\": \"input-number\",\n              \"label\": \"port\",\n              \"name\": \"port\",\n              \"keyboard\": true,\n              \"id\": \"u:3d3695bd7ab2\",\n              \"step\": 1\n            },\n            {\n              \"type\": \"input-text\",\n              \"name\": \"apiKey\",\n              \"placeholder\": \"\",\n              \"id\": \"u:25b0c7b5e5a0\",\n              \"label\": \"apiKey\"\n            },\n            {\n              \"type\": \"input-text\",\n              \"label\": \"model\",\n              \"name\": \"model\",\n              \"id\": \"u:ac0737858444\",\n              \"description\": \"\"\n            },\n            {\n              \"type\": \"input-number\",\n              \"label\": \"maxTokens\",\n              \"name\": \"maxTokens\",\n              \"keyboard\": true,\n              \"id\": \"u:a8cfb52c5e43\",\n              \"step\": 1\n            },\n            {\n              \"type\": \"input-number\",\n              \"label\": \"temperature\",\n              \"name\": \"temperature\",\n              \"keyboard\": true,\n              \"id\": \"u:8797d33941aa\",\n              \"step\": 1\n            },\n            {\n              \"type\": \"input-text\",\n              \"label\": \"proxyUrl\",\n              \"name\": \"proxyUrl\",\n              \"description\": \"\"\n            },\n            {\n              \"type\": \"switch\",\n              \"label\": \"use\",\n              \"option\": \"\",\n              \"name\": \"use\",\n              \"falseValue\": false,\n              \"trueValue\": true,\n              \"id\": \"u:1ac806d7ad60\",\n              \"value\": false\n            }\n          ],\n          \"id\": \"u:186f183e9320\",\n          \"strictMode\": false,\n          \"syncFields\": [],\n          \"tabsMode\": false,\n          \"draggable\": true,\n          \"draggableTip\": \"可拖动排序\",\n          \"tabsStyle\": \"line\",\n          \"tabsLabelTpl\": \"表单项${index+1}\",\n          \"multiLine\": true,\n          \"value\": [{}]\n        }\n      ],\n      \"submitText\": \"\"\n    }\n  ],\n  \"pullRefresh\": { \"disabled\": true },\n  \"regions\": [\"body\"],\n  \"style\": { \"boxShadow\": \" 0px 0px 0px 0px transparent\" },\n  \"asideResizor\": false\n}\n"
  },
  {
    "path": "materials/snippets/设置配置信息/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/设置配置信息/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/设置配置信息/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: (lowcodeContext) => {},\n  onSelect: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    await main.bootstrap();\n  },\n};\n"
  },
  {
    "path": "materials/snippets/设置配置信息/script/src/context.ts",
    "content": "import { CompileContext } from 'lowcode-context';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n} = {\n  lowcodeContext: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/设置配置信息/script/src/controller.ts",
    "content": "import * as vscode from 'vscode';\nimport { CompileContext } from 'lowcode-context';\nimport { getShareData, saveShareData } from '@share/utils/shareData';\nimport { getDynamicFormConfig } from '@share/utils/dynamicForm';\nimport { IMessage } from '@share/WebView/type';\n\ntype RunDynamicFormScript = (\n  message: IMessage<{\n    method: string;\n    params: string;\n    model: object;\n  }>,\n  lowcodeContext: {\n    webview: vscode.Webview;\n  } & CompileContext,\n) => Promise<{\n  /** 立即更新 model */\n  updateModelImmediately: boolean;\n  /** 仅更新参数 */\n  onlyUpdateParams: boolean;\n  params?: string;\n  model: object;\n}>;\n\nexport const getDynamicForm = (\n  message: IMessage,\n  context: {\n    webview: vscode.Webview;\n    task: { task: string; data?: any };\n  } & CompileContext,\n) => {\n  const { materialPath } = context;\n  const model = getShareData();\n  const config = getDynamicFormConfig({\n    vscodeMaterialPath: materialPath,\n    model,\n  });\n  return {\n    schema: config.schema,\n    scripts: config.scripts,\n  };\n};\n\nexport const runDynamicFormScript: RunDynamicFormScript = async (\n  message,\n  lowcodeContext,\n) => {\n  if (handler[message.data.method]) {\n    return handler[message.data.method](message, lowcodeContext);\n  }\n  return Promise.reject(`方法：${message.data.method} 不存在`);\n};\n\nconst handler: {\n  [method: string]: RunDynamicFormScript;\n} = {\n  saveConfig: (message, lowcodeContext) => {\n    saveShareData(message.data.model);\n    return Promise.resolve({\n      model: message.data.model,\n      updateModelImmediately: true,\n      onlyUpdateParams: false,\n      params: '',\n    });\n  },\n};\n"
  },
  {
    "path": "materials/snippets/设置配置信息/script/src/main.ts",
    "content": "import { showWebView } from '@share/WebView';\nimport { routes } from './routes';\nimport { context } from './context';\n\nexport async function bootstrap() {\n  const { lowcodeContext } = context;\n  showWebView({\n    key: 'main',\n    title: '设置配置信息',\n    viewColumn: 3,\n    task: {\n      task: 'route',\n      data: {\n        path: '/dynamicForm',\n        materialPath: lowcodeContext?.materialPath,\n      },\n    },\n    lowcodeContext: {\n      ...lowcodeContext!,\n    },\n    // htmlForWebview: getHtmlForWebview(false),\n    routes,\n  });\n}\n\nconst getHtmlForWebview = (dev = false) => {\n  if (dev) {\n    return `\n\t\t\t\t<!doctype html>\n\t\t\t\t<html lang=\"en\">\n\t\t\t\t\t<head>\n\t\t\t\t\t\t<script type=\"module\">import { injectIntoGlobalHook } from \"http://127.0.0.1:5173/@react-refresh\";\n\t\t\t\t\t\tinjectIntoGlobalHook(window);\n\t\t\t\t\t\twindow.$RefreshReg$ = () => {};\n\t\t\t\t\t\twindow.$RefreshSig$ = () => (type) => type;</script>\n\n\t\t\t\t\t\t<script type=\"module\" src=\"http://127.0.0.1:5173/@vite/client\"></script>\n\t\t\t\t\t\t<script>\n\t\t\t\t\t\t\twindow.vscode = acquireVsCodeApi();\n\t\t\t\t\t\t</script>\n\t\t\t\t\t\t<meta charset=\"UTF-8\" />\n\t\t\t\t\t\t<link rel=\"icon\" type=\"image/svg+xml\" href=\"http://127.0.0.1:5173/vite.svg\" />\n\t\t\t\t\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n\t\t\t\t\t</head>\n\t\t\t\t\t<body>\n\t\t\t\t\t\t<div id=\"root\"></div>\n\t\t\t\t\t\t<script type=\"module\" src=\"http://127.0.0.1:5173/src/main.tsx\"></script>\n\t\t\t\t\t</body>\n\t\t\t\t</html>\n\t\t`;\n  }\n  return `\n\t\t\t<!DOCTYPE html>\n\t\t\t<html>\n\t\t\t<head>\n\t\t\t\t<meta charset=\"utf-8\" />\n\t\t\t\t<meta\n\t\t\t\t\tname=\"viewport\"\n\t\t\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no\"\n\t\t\t\t/>\n\t\t\t\t<script>\n\t\t\t\t   window.vscode = acquireVsCodeApi();\n        </script>\n\t\t\t\t<script type=\"module\" crossorigin src=\"http://lowcode-utools.oss-cn-beijing.aliyuncs.com/vscode.index.js\"></script>\n\t\t\t\t<link rel=\"stylesheet\" crossorigin href=\"http://lowcode-utools.oss-cn-beijing.aliyuncs.com/vscode.index.css\">\n\t\t\t</head>\n\t\t\t<body>\n\t\t\t\t<div id=\"root\"></div>\n\t\t\t</body>\n\t\t</html>\n`;\n};\n"
  },
  {
    "path": "materials/snippets/设置配置信息/script/src/routes.ts",
    "content": "import * as controller from './controller';\n\nexport const routes: Record<string, any> = {\n  runDynamicFormScript: controller.runDynamicFormScript,\n  getDynamicForm: controller.getDynamicForm,\n};\n"
  },
  {
    "path": "materials/snippets/设置配置信息/src/template.ejs",
    "content": "代码片段"
  },
  {
    "path": "materials/snippets/通过 TS 类型做字段映射/config/model.json",
    "content": "{\n\t\"originalType\": \"\",\n\t\"targetType\": \"\",\n\t\"originalVariable\": \"\",\n\t\"targetVariable\": \"\"\n}"
  },
  {
    "path": "materials/snippets/通过 TS 类型做字段映射/config/preview.json",
    "content": "{\n\t\"title\": \"\",\n\t\"description\": \"\",\n\t\"img\": [\n\t\t\"https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg\"\n\t],\n\t\"category\": [],\n\t\"notShowInCommand\": true,\n\t\"notShowInSnippetsList\": true,\n\t\"notShowInintellisense\": true,\n\t\"showInRunSnippetScript\": true,\n\t\"showInRunSnippetScriptOnExplorer\": false,\n\t\"runActivate\": false,\n\t\"schema\": \"amis\",\n\t\"scripts\": [\n\t\t{\n\t\t\t\"method\": \"askChatGPT\",\n\t\t\t\"remark\": \"ask ChatGPT\"\n\t\t}\n\t]\n}"
  },
  {
    "path": "materials/snippets/通过 TS 类型做字段映射/config/schema.json",
    "content": "{\n\t\"type\": \"page\",\n\t\"body\": [\n\t\t{\n\t\t\t\"type\": \"form\",\n\t\t\t\"id\": \"u:67967afb0e69\",\n\t\t\t\"title\": \"\",\n\t\t\t\"body\": [\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"textarea\",\n\t\t\t\t\t\"label\": \"原始类型\",\n\t\t\t\t\t\"name\": \"originalType\",\n\t\t\t\t\t\"id\": \"u:1772600049f6\",\n\t\t\t\t\t\"minRows\": 10,\n\t\t\t\t\t\"maxRows\": 20\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"textarea\",\n\t\t\t\t\t\"label\": \"目标类型\",\n\t\t\t\t\t\"name\": \"targetType\",\n\t\t\t\t\t\"id\": \"u:07bd55b0bd60\",\n\t\t\t\t\t\"minRows\": 10,\n\t\t\t\t\t\"maxRows\": 20\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\"label\": \"原始变量\",\n\t\t\t\t\t\"name\": \"originalVariable\",\n\t\t\t\t\t\"id\": \"u:1bc921a6215e\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\"label\": \"目标变量\",\n\t\t\t\t\t\"name\": \"targetVariable\",\n\t\t\t\t\t\"id\": \"u:0237afad67b1\"\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"submitText\": \"\",\n\t\t\t\"actions\": [],\n\t\t\t\"feat\": \"Insert\"\n\t\t}\n\t],\n\t\"id\": \"u:d87dbf6bf8df\",\n\t\"pullRefresh\": {\n\t\t\"disabled\": true\n\t},\n\t\"regions\": [\n\t\t\"body\"\n\t],\n\t\"style\": {},\n\t\"asideResizor\": false,\n\t\"themeCss\": {\n\t\t\"baseControlClassName\": {\n\t\t\t\"boxShadow:default\": \" 0px 0px 0px 0px transparent\"\n\t\t}\n\t}\n}"
  },
  {
    "path": "materials/snippets/通过 TS 类型做字段映射/script/index.js",
    "content": "const path = require('path');\nconst moduleAlias = require('module-alias');\n\nfunction splitStringByLastKeyword(inputString, keyword) {\n  const lastIndex = inputString.lastIndexOf(keyword);\n\n  if (lastIndex === -1) {\n    return [inputString, ''];\n  }\n\n  const part1 = inputString.slice(0, lastIndex);\n  const part2 = inputString.slice(lastIndex + keyword.length);\n\n  return [part1, part2];\n}\n\nmoduleAlias.addAlias(\n  '@share',\n  path.join(splitStringByLastKeyword(__dirname, 'materials')[0], 'dist/share'),\n);\nconst main = require('../../../../dist/materials/snippets/通过 TS 类型做字段映射/script/src/main');\nconst {\n  context,\n} = require('../../../../dist/materials/snippets/通过 TS 类型做字段映射/script/src/context');\n\nmodule.exports = {\n  beforeCompile: (lowcodeContext) => {},\n  afterCompile: (lowcodeContext) => {},\n  onSelect: async (lowcodeContext) => {\n    context.lowcodeContext = lowcodeContext;\n    await main.bootstrap();\n  },\n};\n"
  },
  {
    "path": "materials/snippets/通过 TS 类型做字段映射/script/src/context.ts",
    "content": "import { CompileContext } from 'lowcode-context';\n\nexport const context: {\n  lowcodeContext?: CompileContext;\n} = {\n  lowcodeContext: undefined,\n};\n"
  },
  {
    "path": "materials/snippets/通过 TS 类型做字段映射/script/src/controller.ts",
    "content": "import * as vscode from 'vscode';\nimport { CompileContext } from 'lowcode-context';\nimport { IMessage } from '@share/WebView/type';\n\ntype RunDynamicFormScript = (\n  message: IMessage<{\n    method: string;\n    params: string;\n    model: any;\n  }>,\n  lowcodeContext: {\n    webview: vscode.Webview;\n  } & CompileContext,\n) => Promise<{\n  /** 立即更新 model */\n  updateModelImmediately: boolean;\n  /** 仅更新参数 */\n  onlyUpdateParams: boolean;\n  params?: string;\n  model: any;\n}>;\n\nexport const runDynamicFormScript: RunDynamicFormScript = async (\n  message,\n  lowcodeContext,\n) => {\n  if (handler[message.data.method]) {\n    return handler[message.data.method](message, lowcodeContext);\n  }\n  return Promise.reject(`方法：${message.data.method} 不存在`);\n};\n\nconst handler: {\n  [method: string]: RunDynamicFormScript;\n} = {\n  askChatGPT: async (message, lowcodeContext) => {\n    const prompt = `目前有变量 ${message.data.model.originalVariable}，类型为：\n\"\"\"\n${message.data.model.originalType}\n\"\"\"\n以及变量 ${message.data.model.targetVariable || 'model'}，类型为：\n\"\"\"\n${message.data.model.targetType}\n\"\"\"\n请根据注释或者字段名称把变量 ${\n      message.data.model.originalVariable\n    } 的每个字段赋值给变量 ${\n      message.data.model.targetVariable || 'model'\n    } 的相应字段，按下面的方式进行赋值：\n\"\"\"\n{\n\ta: ${message.data.model.originalVariable}.a,\n\tb: ${message.data.model.originalVariable}.b,\n\tc: ${message.data.model.originalVariable}.c,\n\td: ${message.data.model.originalVariable}.d,\n}\n\"\"\"\n    `;\n    const res = await lowcodeContext.createChatCompletion({\n      messages: [{ content: prompt, role: 'user' }],\n      showWebview: true,\n    });\n    return {\n      model: message.data.model,\n      updateModelImmediately: false,\n      onlyUpdateParams: true,\n      params: res,\n    };\n  },\n};\n"
  },
  {
    "path": "materials/snippets/通过 TS 类型做字段映射/script/src/main.ts",
    "content": "import { window } from 'vscode';\nimport { showWebView } from '@share/WebView';\nimport { routes } from './routes';\nimport { context } from './context';\n\nexport async function bootstrap() {\n  const { lowcodeContext } = context;\n  showWebView({\n    key: 'main',\n    title: '通过 TS 类型做字段映射',\n    viewColumn: 3,\n    task: {\n      task: 'route',\n      data: {\n        path: '/dynamicForm',\n        materialPath: lowcodeContext?.materialPath,\n      },\n    },\n    lowcodeContext: {\n      ...lowcodeContext!,\n    },\n    htmlForWebview: getHtmlForWebview(false),\n    routes,\n  });\n}\n\nconst getHtmlForWebview = (dev = false) => {\n  if (dev) {\n    return `\n\t\t\t\t<!doctype html>\n\t\t\t\t<html lang=\"en\">\n\t\t\t\t\t<head>\n\t\t\t\t\t\t<script type=\"module\">import { injectIntoGlobalHook } from \"http://127.0.0.1:5173/@react-refresh\";\n\t\t\t\t\t\tinjectIntoGlobalHook(window);\n\t\t\t\t\t\twindow.$RefreshReg$ = () => {};\n\t\t\t\t\t\twindow.$RefreshSig$ = () => (type) => type;</script>\n\n\t\t\t\t\t\t<script type=\"module\" src=\"http://127.0.0.1:5173/@vite/client\"></script>\n\t\t\t\t\t\t<script>\n\t\t\t\t\t\t\twindow.vscode = acquireVsCodeApi();\n\t\t\t\t\t\t</script>\n\t\t\t\t\t\t<meta charset=\"UTF-8\" />\n\t\t\t\t\t\t<link rel=\"icon\" type=\"image/svg+xml\" href=\"http://127.0.0.1:5173/vite.svg\" />\n\t\t\t\t\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n\t\t\t\t\t</head>\n\t\t\t\t\t<body>\n\t\t\t\t\t\t<div id=\"root\"></div>\n\t\t\t\t\t\t<script type=\"module\" src=\"http://127.0.0.1:5173/src/main.tsx\"></script>\n\t\t\t\t\t</body>\n\t\t\t\t</html>\n\t\t`;\n  }\n  return `\n\t\t\t<!DOCTYPE html>\n\t\t\t<html>\n\t\t\t<head>\n\t\t\t\t<meta charset=\"utf-8\" />\n\t\t\t\t<meta\n\t\t\t\t\tname=\"viewport\"\n\t\t\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no\"\n\t\t\t\t/>\n\t\t\t\t<script>\n\t\t\t\t   window.vscode = acquireVsCodeApi();\n        </script>\n\t\t\t\t<script type=\"module\" crossorigin src=\"http://lowcode-utools.oss-cn-beijing.aliyuncs.com/vscode.index.js\"></script>\n\t\t\t\t<link rel=\"stylesheet\" crossorigin href=\"http://lowcode-utools.oss-cn-beijing.aliyuncs.com/vscode.index.css\">\n\t\t\t</head>\n\t\t\t<body>\n\t\t\t\t<div id=\"root\"></div>\n\t\t\t</body>\n\t\t</html>\n`;\n};\n"
  },
  {
    "path": "materials/snippets/通过 TS 类型做字段映射/script/src/routes.ts",
    "content": "import * as controller from './controller';\n\nexport const routes: Record<string, any> = {\n  runDynamicFormScript: controller.runDynamicFormScript,\n};\n"
  },
  {
    "path": "materials/snippets/通过 TS 类型做字段映射/src/template.ejs",
    "content": "代码片段"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"lowcode-materials\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"compile\": \"tsc --project tsconfig.compiler.json --skipLibCheck\",\n    \"uTools\": \"node ./uTools.js\",\n    \"build\": \"npm run prod\",\n    \"prod\": \"node ./buildMaterials.js prod && npm run compile && npm run uTools\",\n    \"dev\": \"node ./buildMaterials.js dev && npm run compile && npm run uTools\",\n    \"lint\": \"eslint --ext .ts,.tsx,.js,.jsx materials/\",\n    \"start:dev\": \"cross-env NODE_ENV=dev nest start --watch\",\n    \"tsc\": \"tsc  --noEmit --skipLibCheck\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/lowcode-scaffold/lowcode-materials.git\"\n  },\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"bugs\": {\n    \"url\": \"https://github.com/lowcode-scaffold/lowcode-materials/issues\"\n  },\n  \"homepage\": \"https://github.com/lowcode-scaffold/lowcode-materials#readme\",\n  \"dependencies\": {\n    \"@babel/parser\": \"^7.22.10\",\n    \"@google/generative-ai\": \"^0.1.3\",\n    \"@nestjs/common\": \"^10.2.2\",\n    \"@nestjs/config\": \"^3.0.0\",\n    \"@nestjs/core\": \"^10.2.2\",\n    \"@nestjs/platform-express\": \"^10.2.2\",\n    \"ajv\": \"^8.12.0\",\n    \"ali-oss\": \"^6.21.0\",\n    \"ast-types\": \"^0.14.2\",\n    \"axios\": \"^1.5.0\",\n    \"ejs\": \"^3.1.9\",\n    \"execa\": \"^4.0.1\",\n    \"fs-extra\": \"^11.1.1\",\n    \"generate-schema\": \"^2.6.0\",\n    \"glob\": \"^7.1.6\",\n    \"html-entities\": \"^2.4.0\",\n    \"json-schema-to-typescript\": \"^13.1.1\",\n    \"jsonminify\": \"^0.4.2\",\n    \"mitt\": \"^3.0.1\",\n    \"mockjs\": \"^1.1.0\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"recast\": \"^0.23.4\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\",\n    \"strip-comments\": \"^2.0.1\",\n    \"tar\": \"^7.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tunnel\": \"^0.0.6\",\n    \"typescript\": \"^5.1.3\",\n    \"typescript-json-schema\": \"^0.60.0\",\n    \"undici\": \"^6.4.0\"\n  },\n  \"devDependencies\": {\n    \"@electron/remote\": \"^2.1.2\",\n    \"@nestjs/cli\": \"^10.1.16\",\n    \"@nestjs/schematics\": \"^10.0.2\",\n    \"@types/ejs\": \"^3.1.3\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/fs-extra\": \"^11.0.1\",\n    \"@types/glob\": \"^7.1.1\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/react\": \"^18.2.45\",\n    \"@types/react-dom\": \"^18.2.18\",\n    \"@types/vscode\": \"^1.79.1\",\n    \"@typescript-eslint/eslint-plugin\": \"^6.3.0\",\n    \"@typescript-eslint/parser\": \"^6.3.0\",\n    \"cross-env\": \"^7.0.3\",\n    \"dotenv-cli\": \"^7.3.0\",\n    \"electron\": \"^29.1.0\",\n    \"esbuild\": \"^0.20.2\",\n    \"eslint\": \"^8.47.0\",\n    \"eslint-config-airbnb-base\": \"^15.0.0\",\n    \"eslint-config-prettier\": \"^9.0.0\",\n    \"eslint-plugin-import\": \"^2.28.0\",\n    \"eslint-plugin-prettier\": \"^5.0.0\",\n    \"module-alias\": \"^2.2.3\",\n    \"prettier\": \"^3.0.1\",\n    \"tslib\": \"^2.5.3\",\n    \"utools-api-types\": \"^4.0.0\"\n  }\n}"
  },
  {
    "path": "scripts/ClipboardImage/linux.sh",
    "content": "#!/bin/sh\n\n# require xclip(see http://stackoverflow.com/questions/592620/check-if-a-program-exists-from-a-bash-script/677212#677212)\ncommand -v xclip >/dev/null 2>&1 || { echo >&1 \"no xclip\"; exit 1; }\n\n# write image in clipboard to file (see http://unix.stackexchange.com/questions/145131/copy-image-from-clipboard-to-file)\nif\nxclip -selection clipboard -target image/png -o >/dev/null 2>&1\nthen\nxclip -selection clipboard -target image/png -o >$1 2>/dev/null\necho $1\nelse\necho \"no image\"\nfi"
  },
  {
    "path": "scripts/ClipboardImage/mac.applescript",
    "content": "property fileTypes : {{«class PNGf», \".png\"}}\n\non run argv\n\tif argv is {} then\n\t\treturn \"\"\n\tend if\n\t\n\tset imagePath to (item 1 of argv)\n\tset theType to getType()\n\t\n\tif theType is not missing value then\t\t\n\t\ttry\n\t\t\tset myFile to (open for access imagePath with write permission)\n\t\t\tset eof myFile to 0\n\t\t\twrite (the clipboard as (first item of theType)) to myFile\n\t\t\tclose access myFile\n\t\t\treturn (POSIX path of imagePath)\n\t\ton error\n\t\t\ttry\n\t\t\t\tclose access myFile\n\t\t\tend try\n\t\t\treturn \"\"\n\t\tend try\n\telse\n\t\treturn \"no image\"\n\tend if\nend run\n\non getType()\n\trepeat with aType in fileTypes\n\t\trepeat with theInfo in (clipboard info)\n\t\t\tif (first item of theInfo) is equal to (first item of aType) then return aType\n\t\tend repeat\n\tend repeat\n\treturn missing value\nend getType"
  },
  {
    "path": "scripts/ClipboardImage/pc.ps1",
    "content": "param($imagePath)\n\n# Adapted from https://github.com/octan3/img-clipboard-dump/blob/master/dump-clipboard-png.ps1\n\nAdd-Type -Assembly PresentationCore\n$img = [Windows.Clipboard]::GetImage()\n\nif ($img -eq $null) {\n    \"no image\"\n    Exit 1\n}\n\nif (-not $imagePath) {\n    \"no image\"\n    Exit 1\n}\n\n$fcb = new-object Windows.Media.Imaging.FormatConvertedBitmap($img, [Windows.Media.PixelFormats]::Rgb24, $null, 0)\n$stream = [IO.File]::Open($imagePath, \"OpenOrCreate\")\n$encoder = New-Object Windows.Media.Imaging.PngBitmapEncoder\n$encoder.Frames.Add([Windows.Media.Imaging.BitmapFrame]::Create($fcb)) | out-null\n$encoder.Save($stream) | out-null\n$stream.Dispose() | out-null\n\n$imagePath"
  },
  {
    "path": "share/BaiduOCR/index.ts",
    "content": "import { request } from './request';\n\n// #region 通用文字识别（标准版）\nexport interface IGeneralBasicResult {\n  words_result: {\n    words: string;\n  }[];\n  words_result_num: number;\n  log_id: number;\n}\n\nexport interface IGeneralBasicData {\n  image: string;\n  detect_direction?: boolean;\n  paragraph?: boolean;\n  probability?: boolean;\n}\n/**\n * 通用文字识别（标准版）\n * https://cloud.baidu.com/doc/OCR/s/zk3h7xz52\n */\nexport function generalBasic(data: IGeneralBasicData) {\n  return request<IGeneralBasicResult>({\n    url: `https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic`,\n    method: 'POST',\n    data,\n  });\n}\n// #endregion\n\n// #region 通用文字识别（标准含位置版）\nexport interface IGeneralResult {\n  words_result: {\n    words: string;\n    location: {\n      top: number;\n      left: number;\n      width: number;\n      height: number;\n    };\n  }[];\n  words_result_num: number;\n  log_id: number;\n}\n\nexport interface IGeneralData {\n  image: string;\n  detect_direction?: boolean;\n  paragraph?: boolean;\n  probability?: boolean;\n}\n\n/**\n * 通用文字识别（标准含位置版）\n * https://cloud.baidu.com/doc/OCR/s/vk3h7y58v\n */\nexport function general(data: IGeneralData) {\n  return request<IGeneralResult>({\n    url: `https://aip.baidubce.com/rest/2.0/ocr/v1/general`,\n    method: 'POST',\n    data,\n  });\n}\n\n// #endregion\n\n// #region 通用文字识别（高精度版）\nexport interface IAccurateBasicResult {\n  words_result: {\n    words: string;\n  }[];\n  words_result_num: number;\n  log_id: number;\n}\n\nexport interface IAccurateBasicData {\n  image: string;\n}\n\n/**\n * 通用文字识别（高精度版）\n * https://cloud.baidu.com/doc/OCR/s/1k3h7y3db\n */\nexport function accurateBasic(data: IAccurateBasicData) {\n  return request<IAccurateBasicResult>({\n    url: `https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic`,\n    method: 'POST',\n    data,\n  });\n}\n\n// #endregion\n// #region 通用文字识别（高精度含位置版）\nexport interface IAccurateResult {\n  words_result: {\n    words: string;\n    location: {\n      top: number;\n      left: number;\n      width: number;\n      height: number;\n    };\n  }[];\n  words_result_num: number;\n  log_id: number;\n}\n\nexport interface IAccurateData {\n  image: string;\n}\n/**\n * 通用文字识别（高精度含位置版）\n * https://cloud.baidu.com/doc/OCR/s/tk3h7y2aq\n */\nexport function accurate(data: IAccurateData) {\n  return request<IAccurateResult>({\n    url: `https://aip.baidubce.com/rest/2.0/ocr/v1/accurate`,\n    method: 'POST',\n    data,\n  });\n}\n// #endregion\n\n// #region 办公文档识别\nexport interface IDocAnalysisOfficeResult {\n  results: {\n    words: {\n      word: string;\n      words_location: {\n        left: number;\n        height: number;\n        width: number;\n        top: number;\n      };\n    };\n    words_type: string;\n  }[];\n  results_num: number;\n  log_id: number;\n}\n\nexport interface IDocAnalysisOfficeData {\n  image: string;\n}\n/**\n * 办公文档识别\n * https://cloud.baidu.com/doc/OCR/s/ykg9c09ji\n */\nexport function docAnalysisOffice(data: IDocAnalysisOfficeData) {\n  return request<IDocAnalysisOfficeResult>({\n    url: `https://aip.baidubce.com/rest/2.0/ocr/v1/doc_analysis_office`,\n    method: 'POST',\n    data,\n  });\n}\n// #endregion\n"
  },
  {
    "path": "share/BaiduOCR/request.ts",
    "content": "import axios, { AxiosRequestConfig } from 'axios';\n\nconst instance = axios.create({\n  timeout: 30 * 1000,\n});\n\n// 请求拦截\ninstance.interceptors.request.use(\n  // @ts-ignore\n  async (config) => {\n    let token = '';\n    if (!config.url?.includes('/oauth/2.0/token')) {\n      token = await getAccessToken();\n    }\n    return {\n      ...config,\n      headers: {\n        ...config.headers,\n        'content-type': 'application/x-www-form-urlencoded',\n      },\n      params: {\n        ...config.params,\n        access_token: token,\n      },\n    };\n  },\n  (error) => Promise.reject(error),\n);\n\n// 响应拦截\ninstance.interceptors.response.use(\n  (res) => {\n    if (res.data && res.data.error_msg) {\n      return Promise.reject(res.data.error_msg);\n    }\n    return Promise.resolve(res.data);\n  },\n  (error) => Promise.reject(error),\n);\n\ntype Request = <T = unknown>(config: AxiosRequestConfig) => Promise<T>;\n\nexport const request = instance.request as Request;\n\nconst getAccessToken = async () => {\n  const res = await request<{ access_token: string }>({\n    url: 'https://aip.baidubce.com/oauth/2.0/token',\n    method: 'POST',\n    params: {\n      client_id: 'xxxxx',\n      client_secret: 'xxxxxxxx',\n      grant_type: 'client_credentials',\n    },\n  });\n  return res.access_token;\n};\n"
  },
  {
    "path": "share/JSONSchemaChat/index.ts",
    "content": "import Ajv from 'ajv';\nimport { StatusBarAlignment, window } from 'vscode';\nimport { Success, Error, error, success } from './result';\n\nexport async function translate<T extends object>(option: {\n  schema: string;\n  request: string;\n  createChatCompletion: (options: {\n    messages: {\n      role: 'system' | 'user' | 'assistant';\n      content: string;\n    }[];\n    handleChunk?: ((data: { text?: string }) => void) | undefined;\n    showWebview?: boolean;\n  }) => Promise<string>;\n  showWebview?: boolean;\n  /**\n   * @description 完整的 prompt，若提供则内部不再组合 prompt\n   * @type {string}\n   */\n  completePrompt?: string;\n  extendValidate?: (jsonObject: T) => Error | Success<T>;\n}) {\n  let requestPrompt =\n    option.completePrompt ||\n    `你是一个根据以下 JSON Schema 定义将用户请求转换为相应 JSON 数据的服务，并且按照 JSON Schema 中 description 的描述对字段进行处理:\\n` +\n      `\\`\\`\\`\\n${option.schema}\\`\\`\\`\\n` +\n      `The following is a user request:\\n` +\n      `\"\"\"\\n${option.request}\\n\"\"\"\\n` +\n      `The following is the user request translated into a JSON data with 2 spaces of indentation and no properties with the value undefined:\\n`;\n  let tryCount = 0;\n  // eslint-disable-next-line no-unreachable-loop, no-constant-condition\n  while (true) {\n    const statusBarItem = window.createStatusBarItem(StatusBarAlignment.Left);\n    statusBarItem.text = '$(sync~spin) Ask ChatGPT...';\n    statusBarItem.show();\n    // eslint-disable-next-line no-await-in-loop\n    const responseText = await option\n      .createChatCompletion({\n        messages: [{ role: 'user', content: requestPrompt }],\n        handleChunk: undefined,\n        showWebview: option.showWebview,\n      })\n      .finally(() => {\n        statusBarItem.hide();\n        statusBarItem.dispose();\n      });\n    let validation = validate<T>(\n      responseText.replace(/```/g, ''),\n      option.schema,\n    );\n    if (validation.success) {\n      // 走额外的校验\n      if (option.extendValidate) {\n        validation = option.extendValidate(validation.data);\n        if (validation.success) {\n          return validation;\n        }\n      } else {\n        return validation;\n      }\n    }\n    if (tryCount > 3) {\n      return validation;\n    }\n    requestPrompt += `${responseText}\\n${createRepairPrompt(\n      validation.message,\n    )}`;\n    tryCount++;\n  }\n}\n\nfunction createRepairPrompt(validationError: string) {\n  return (\n    `The JSON object is invalid for the following reason:\\n` +\n    `\"\"\"\\n${validationError}\\n\"\"\"\\n` +\n    `The following is a revised JSON object:\\n`\n  );\n}\n\nfunction validate<T extends object>(jsonText: string, schema: string) {\n  let jsonObject;\n  try {\n    jsonObject = JSON.parse(jsonText) as object;\n  } catch (e) {\n    return error(e instanceof SyntaxError ? e.message : 'JSON parse error');\n  }\n  stripNulls(jsonObject);\n  const ajv = new Ajv();\n  const jsonValidate = ajv.compile(JSON.parse(schema));\n  const valid = jsonValidate(jsonObject);\n  if (!valid) {\n    console.log(jsonValidate.errors);\n    return error(\n      jsonValidate.errors?.map((s) => s.message || s.keyword).join(',') || '',\n    );\n  }\n  return success<T>(jsonObject);\n}\n\nfunction stripNulls(obj: any) {\n  let keysToDelete: string[] | undefined;\n  // eslint-disable-next-line no-restricted-syntax, guard-for-in\n  for (const k in obj) {\n    const value = obj[k];\n    if (value === null) {\n      (keysToDelete ??= []).push(k);\n    } else {\n      if (Array.isArray(value)) {\n        if (value.some((x) => x === null)) {\n          obj[k] = value.filter((x) => x !== null);\n        }\n      }\n      if (typeof value === 'object') {\n        stripNulls(value);\n      }\n    }\n  }\n  if (keysToDelete) {\n    // eslint-disable-next-line no-restricted-syntax\n    for (const k of keysToDelete) {\n      delete obj[k];\n    }\n  }\n}\n"
  },
  {
    "path": "share/JSONSchemaChat/result.ts",
    "content": "export type Success<T> = { success: true; data: T };\n\nexport type Error = { success: false; message: string };\n\nexport type Result<T> = Success<T> | Error;\n\nexport function success<T>(data: T): Success<T> {\n  return { success: true, data };\n}\n\nexport function error(message: string): Error {\n  return { success: false, message };\n}\n\nexport function getData<T>(result: Result<T>) {\n  if (result.success) {\n    return result.data;\n  }\n  throw new Error(result.message);\n}\n"
  },
  {
    "path": "share/LLM/gemini.ts",
    "content": "import { Content, GoogleGenerativeAI, Part } from '@google/generative-ai';\nimport { setGlobalDispatcher, ProxyAgent } from 'undici';\nimport { oneAPIConfig } from '../utils/shareData';\n\ntype Message = (\n  | {\n      role: 'system';\n      content: string;\n    }\n  | {\n      role: 'user';\n      content:\n        | string\n        | (\n            | {\n                type: 'image_url';\n                image_url: { url: string };\n              }\n            | { type: 'text'; text: string }\n          )[];\n    }\n)[];\n\nexport const createChatCompletion = async (options: {\n  apiKey?: string;\n  model?: 'gemini-pro' | 'gemini-pro-vision';\n  maxTokens?: number;\n  hostname?: string;\n  apiPath?: string;\n  messages: Message;\n  handleChunk?: (data: { text?: string }) => void;\n  topP?: number;\n  temperature?: number;\n  proxyUrl?: string;\n}) => {\n  const config = oneAPIConfig();\n  if (options.proxyUrl || config?.proxyUrl) {\n    const dispatcher = new ProxyAgent({\n      uri: new URL(options.proxyUrl || config?.proxyUrl || '').toString(),\n    });\n    setGlobalDispatcher(dispatcher);\n  }\n  const genAI = new GoogleGenerativeAI(options.apiKey || config?.apiKey || '');\n  const model = genAI.getGenerativeModel({\n    model: options.model || config?.model || '',\n    generationConfig: {\n      maxOutputTokens: options.maxTokens || config?.maxTokens,\n      temperature: options.temperature,\n      topP: options.topP,\n    },\n  });\n  try {\n    const result = await model.generateContentStream({\n      contents: openAiMessageToGeminiMessage(options.messages),\n    });\n    let combinedResult = '';\n    // eslint-disable-next-line no-restricted-syntax\n    for await (const chunk of result.stream) {\n      const chunkText = chunk.text();\n      if (options.handleChunk) {\n        options.handleChunk({ text: chunkText });\n      }\n      combinedResult += chunkText;\n    }\n    return combinedResult;\n  } catch (ex: any) {\n    if (options.handleChunk) {\n      options.handleChunk({ text: ex.toString() });\n    }\n    return ex.toString();\n  }\n};\n\nconst openAiMessageToGeminiMessage = (messages: Message): Content[] => {\n  const result: Content[] = [];\n  const hasImage = messages.some(\n    (s) =>\n      Array.isArray(s.content) && s.content.some((c) => c.type === 'image_url'),\n  );\n  if (hasImage) {\n    result.push({ role: 'user', parts: [] });\n    const partsText: string[] = [];\n    let imagePart!: Part;\n    for (let i = 0; i < messages.length; i++) {\n      const { role, content } = messages[i];\n      if (role === 'system') {\n        partsText.push(content);\n        // eslint-disable-next-line no-continue\n        continue;\n      }\n\n      if (content == null || typeof content === 'string') {\n        partsText.push(content || '');\n      } else {\n        for (let j = 0; j < content.length; j++) {\n          const item = content[j];\n          if (item.type === 'text') {\n            partsText.push(item.text || '');\n          } else {\n            imagePart = parseBase64(\n              (item as { type: 'image_url'; image_url: { url: string } })\n                .image_url.url,\n            );\n          }\n        }\n      }\n    }\n    result[0].parts = [{ text: partsText.join('\\n') }, imagePart];\n  } else {\n    for (let i = 0; i < messages.length; i++) {\n      const { role, content } = messages[i];\n      const parts: Part[] = [];\n      if (role === 'system') {\n        result.push({ role: 'user', parts: [{ text: content as string }] });\n        result.push({ role: 'model', parts: [{ text: '' }] });\n        // eslint-disable-next-line no-continue\n        continue;\n      }\n\n      if (content == null || typeof content === 'string') {\n        parts.push({ text: content?.toString() ?? '' });\n      } else {\n        for (let j = 0; j < content.length; j++) {\n          const item = content[j];\n          parts.push(\n            item.type === 'text'\n              ? { text: item.text }\n              : parseBase64(\n                  (item as { type: 'image_url'; image_url: { url: string } })\n                    .image_url.url,\n                ),\n          );\n        }\n      }\n\n      result.push({ role: role === 'user' ? 'user' : 'model', parts });\n\n      if (\n        i < messages.length - 1 &&\n        messages[i + 1].role === 'user' &&\n        role === 'user'\n      ) {\n        result.push({ role: 'model', parts: [{ text: '' }] });\n      }\n    }\n  }\n  return result;\n};\n\nconst parseBase64 = (base64: string): Part => {\n  if (!base64.startsWith('data:')) {\n    return { text: '' };\n  }\n  const [m, data, ..._arr] = base64.split(',');\n  const mimeType = m.match(/:(?<mime>.*?);/)?.groups?.mime ?? 'img/png';\n  return {\n    inlineData: {\n      mimeType,\n      data,\n    },\n  };\n};\n"
  },
  {
    "path": "share/LLM/geminiProxy.ts",
    "content": "/* eslint-disable no-continue */\n/* eslint-disable no-shadow */\nimport * as https from 'https';\nimport { TextDecoder } from 'util';\nimport tunnel from 'tunnel';\n\nconst agent = tunnel.httpsOverHttp({\n  proxy: {\n    host: '127.0.0.1',\n    port: 7890,\n  },\n});\n\nexport const createChatCompletion = (options: {\n  model?: string;\n  maxTokens?: number;\n  messages: {\n    role: 'system' | 'user' | 'assistant';\n    content:\n      | string\n      | (\n          | {\n              type: 'image_url';\n              image_url: { url: string };\n            }\n          | { type: 'text'; text: string }\n        )[];\n  }[];\n  handleChunk?: (data: { text?: string }) => void;\n}) =>\n  new Promise<string>((resolve, reject) => {\n    let combinedResult = '';\n    const error = '发生错误：';\n    const request = https.request(\n      {\n        hostname: 'api.gemini-chat.pro', // https://github.com/blacksev/Gemini-Next-Web API\n        port: 443,\n        path: '/v1/chat/completions',\n        method: 'POST',\n        headers: {\n          'Content-Type': 'application/json',\n          Referer: 'https://gemini-chat.pro/',\n          Origin: 'https://gemini-chat.pro',\n        },\n        agent,\n      },\n      (res) => {\n        let preDataLast = '';\n        res.on('data', async (chunk) => {\n          const text = new TextDecoder('utf-8').decode(chunk);\n          const data = text.split('\\n\\n').filter((s) => s);\n          for (let i = 0; i < data.length; i++) {\n            try {\n              let element = data[i];\n              if (i === data.length - 1 && !data[i].endsWith('}')) {\n                preDataLast = data[i];\n                continue;\n              }\n              if (element.startsWith('data: ')) {\n                if (element.trim() === 'data:') {\n                  // 处理只返回了 data: 的情况\n                  continue;\n                }\n              } else {\n                // 处理没有 data 开头\n                element = preDataLast + element;\n              }\n              if (element.includes('data: ')) {\n                if (element.includes('[DONE]')) {\n                  if (options.handleChunk) {\n                    options.handleChunk({ text: '' });\n                  }\n                  continue;\n                }\n                // remove 'data: '\n                const data = JSON.parse(element.replace('data: ', ''));\n                if (data.finish_reason === 'stop') {\n                  if (options.handleChunk) {\n                    options.handleChunk({ text: '' });\n                  }\n                  continue;\n                }\n                const openaiRes = data.choices[0].delta.content;\n                console.log(openaiRes);\n                if (openaiRes) {\n                  if (options.handleChunk) {\n                    options.handleChunk({\n                      text: openaiRes.replaceAll('\\\\n', '\\n'),\n                    });\n                  }\n                  combinedResult += openaiRes;\n                }\n              } else {\n                console.log('no includes data: ', element);\n              }\n            } catch (e) {\n              console.error({\n                e: (e as Error).toString(),\n                element: data[i],\n              });\n              // error = (e as Error).toString();\n            }\n          }\n        });\n        res.on('error', (e) => {\n          if (options.handleChunk) {\n            options.handleChunk({\n              text: e.toString(),\n            });\n          }\n          reject(e);\n        });\n        res.on('end', () => {\n          if (error !== '发生错误：') {\n            if (options.handleChunk) {\n              options.handleChunk({\n                text: error,\n              });\n            }\n          }\n          resolve(combinedResult || error);\n        });\n      },\n    );\n    const body = {\n      model: options.model,\n      messages: options.messages,\n      stream: true,\n      max_tokens: options.maxTokens,\n      presence_penalty: 0,\n      temperature: 0.5,\n      top_p: 1,\n      frequency_penalty: 0,\n    };\n    request.on('error', (error) => {\n      // eslint-disable-next-line no-unused-expressions\n      options.handleChunk && options.handleChunk({ text: error.toString() });\n      resolve(error.toString());\n      // emitter.emit('chatGPTComplete', error.toString());\n    });\n    request.write(JSON.stringify(body));\n    request.end();\n  });\n"
  },
  {
    "path": "share/LLM/index.ts",
    "content": "import * as vscode from 'vscode';\nimport { CompileContext } from 'lowcode-context';\nimport { oneAPIConfig } from '../utils/shareData';\nimport { showWebView } from '../WebView';\nimport { emitter } from '../utils/emitter';\nimport * as gemini from './gemini';\nimport * as geminiProxy from './geminiProxy';\nimport * as openai from './openai';\n\nconst API_KEY = 'lowcode.GeminiKey';\n\ntype Message = (\n  | {\n      role: 'system';\n      content: string;\n    }\n  | {\n      role: 'user';\n      content:\n        | string\n        | (\n            | {\n                type: 'image_url';\n                image_url: { url: string };\n              }\n            | { type: 'text'; text: string }\n          )[];\n    }\n)[];\n\nexport const createChatCompletion = async (options: {\n  messages: Message;\n  handleChunk?: (data: { text?: string }) => void;\n  lowcodeContext: CompileContext;\n  llm?: string;\n}) => {\n  const config = oneAPIConfig();\n  if (options.llm === 'gemini') {\n    const apiKey = config?.apiKey;\n\n    if (!apiKey) {\n      if (options.handleChunk) {\n        options.handleChunk({ text: 'Please config your api key' });\n      }\n      return 'Please config your api key';\n    }\n    const res = await gemini.createChatCompletion({\n      messages: options.messages,\n      model: options.messages.some(\n        (s) =>\n          Array.isArray(s.content) &&\n          s.content.some((c) => c.type === 'image_url'),\n      )\n        ? 'gemini-pro-vision'\n        : 'gemini-pro',\n      apiKey,\n      handleChunk(data) {\n        if (options.handleChunk) {\n          options.handleChunk(data);\n          emitter.emit('chatGPTChunck', data);\n        }\n      },\n      proxyUrl: config?.proxyUrl || 'http://127.0.0.1:7890',\n    });\n    emitter.emit('chatGPTComplete', res);\n    return res;\n  }\n  if (options.llm === 'geminiProxy') {\n    const res = await geminiProxy.createChatCompletion({\n      messages: options.messages,\n      model: options.messages.some(\n        (s) =>\n          Array.isArray(s.content) &&\n          s.content.some((c) => c.type === 'image_url'),\n      )\n        ? 'gemini-pro-vision'\n        : 'gemini-pro',\n      maxTokens: 4096,\n      handleChunk(data) {\n        if (options.handleChunk) {\n          options.handleChunk(data);\n          emitter.emit('chatGPTChunck', data);\n        }\n      },\n    });\n    emitter.emit('chatGPTComplete', res);\n    return res;\n  }\n  const res = await openai.createChatCompletion({\n    messages: options.messages,\n    handleChunk(data) {\n      if (options.handleChunk) {\n        options.handleChunk(data);\n        emitter.emit('chatGPTChunck', data);\n      }\n    },\n  });\n  emitter.emit('chatGPTComplete', res);\n  return res;\n};\n\nexport const createChatCompletionShowWebView = (options: {\n  messages: Message;\n  handleChunk?: (data: { text?: string }) => void;\n  lowcodeContext: CompileContext;\n  llm?: string;\n  htmlForWebview?: string;\n}) => {\n  // 打开 webview，使用 emitter 监听结果，把结果回传给 script\n  showWebView({\n    key: 'main',\n    lowcodeContext: options.lowcodeContext,\n    task: {\n      task: 'askLLM',\n      data: {\n        content: options.messages.map((m) => m.content).join('\\n'),\n        llm: options.llm,\n      },\n    },\n    htmlForWebview: options.htmlForWebview,\n  });\n  return new Promise<string>((resolve) => {\n    emitter.on('chatGPTChunck', (data) => {\n      if (options.handleChunk) {\n        options.handleChunk(data);\n      }\n    });\n    emitter.on('chatGPTComplete', (data) => {\n      resolve(data);\n      emitter.off('chatGPTChunck');\n      emitter.off('chatGPTComplete');\n    });\n  });\n};\n"
  },
  {
    "path": "share/LLM/openai.ts",
    "content": "/* eslint-disable no-continue */\n/* eslint-disable no-shadow */\nimport * as https from 'https';\nimport * as http from 'http';\nimport { TextDecoder } from 'util';\nimport { workspace } from 'vscode';\nimport { oneAPIConfig } from '../utils/shareData';\n\ntype ChatGPTConfig = {\n  hostname: string;\n  apiPath: string;\n  apiKey: string;\n  model: string;\n  maxTokens: number;\n  temperature: number;\n};\nexport const getChatGPTConfig: () => ChatGPTConfig = () => {\n  const hostname = workspace\n    .getConfiguration('lowcode')\n    .get<string>('hostname', 'api.openai.com');\n  const apiPath = workspace\n    .getConfiguration('lowcode')\n    .get<string>('apiPath', '/v1/chat/completions');\n  const apiKey = workspace\n    .getConfiguration('lowcode')\n    .get<string>('apiKey', '');\n  const model = workspace\n    .getConfiguration('lowcode')\n    .get<string>('model', 'gpt-3.5-turbo');\n  const maxTokens = workspace\n    .getConfiguration('lowcode')\n    .get<number>('maxTokens', 2000);\n  const temperature = workspace\n    .getConfiguration('lowcode')\n    .get<number>('temperature', 0.3);\n\n  return {\n    hostname,\n    apiPath,\n    apiKey,\n    model,\n    maxTokens,\n    temperature,\n  };\n};\n\nexport const createChatCompletion = (options: {\n  apiKey?: string;\n  model?: string;\n  maxTokens?: number;\n  hostname?: string;\n  apiPath?: string;\n  port?: number;\n  notHttps?: boolean;\n  messages: {\n    role: 'system' | 'user' | 'assistant';\n    content:\n      | string\n      | (\n          | {\n              type: 'image_url';\n              image_url: { url: string };\n            }\n          | { type: 'text'; text: string }\n        )[];\n  }[];\n  handleChunk?: (data: { text?: string }) => void;\n}) =>\n  new Promise<string>((resolve, reject) => {\n    const config = oneAPIConfig();\n    let combinedResult = '';\n    const error = '发生错误：';\n    const h = config?.notHttps || options.notHttps ? http : https;\n    const request = h.request(\n      {\n        hostname:\n          options.hostname ||\n          config?.hostname ||\n          getChatGPTConfig().hostname ||\n          'api.openai.com',\n        port: options.port || config?.port || 443,\n        path:\n          options.apiPath ||\n          config?.apiPath ||\n          getChatGPTConfig().apiPath ||\n          '/v1/chat/completions',\n        method: 'POST',\n        headers: {\n          'Content-Type': 'application/json',\n          Authorization: `Bearer ${\n            options.apiKey || config?.apiKey || getChatGPTConfig().apiKey\n          }`,\n        },\n      },\n      (res) => {\n        let preDataLast = '';\n        res.on('data', async (chunk) => {\n          const text = new TextDecoder('utf-8').decode(chunk);\n          const data = text.split('\\n\\n').filter((s) => s);\n          for (let i = 0; i < data.length; i++) {\n            try {\n              let element = data[i];\n              if (i === data.length - 1 && !data[i].endsWith('}')) {\n                preDataLast = data[i];\n                continue;\n              }\n              if (element.startsWith('data: ')) {\n                if (element.trim() === 'data:') {\n                  // 处理只返回了 data: 的情况\n                  continue;\n                }\n              } else {\n                // 处理没有 data 开头\n                element = preDataLast + element;\n              }\n              if (element.includes('data: ')) {\n                if (element.includes('[DONE]')) {\n                  if (options.handleChunk) {\n                    options.handleChunk({ text: '' });\n                  }\n                  continue;\n                }\n                // remove 'data: '\n                const data = JSON.parse(element.replace('data: ', ''));\n                if (data.finish_reason === 'stop') {\n                  if (options.handleChunk) {\n                    options.handleChunk({ text: '' });\n                  }\n                  continue;\n                }\n                const openaiRes = data.choices[0].delta.content;\n                console.log(openaiRes);\n                if (openaiRes) {\n                  if (options.handleChunk) {\n                    options.handleChunk({\n                      text: openaiRes.replaceAll('\\\\n', '\\n'),\n                    });\n                  }\n                  combinedResult += openaiRes;\n                }\n              } else {\n                console.log('no includes data: ', element);\n              }\n            } catch (e) {\n              console.error({\n                e: (e as Error).toString(),\n                element: data[i],\n              });\n              // error = (e as Error).toString();\n            }\n          }\n        });\n        res.on('error', (e) => {\n          if (options.handleChunk) {\n            options.handleChunk({\n              text: e.toString(),\n            });\n          }\n          reject(e);\n        });\n        res.on('end', () => {\n          if (error !== '发生错误：') {\n            if (options.handleChunk) {\n              options.handleChunk({\n                text: error,\n              });\n            }\n          }\n          resolve(combinedResult || error);\n        });\n      },\n    );\n    const body = {\n      model: options.model || config?.model || getChatGPTConfig().model,\n      messages: options.messages,\n      stream: true,\n      max_tokens:\n        options.maxTokens || config?.maxTokens || getChatGPTConfig().maxTokens,\n    };\n    request.on('error', (error) => {\n      // eslint-disable-next-line no-unused-expressions\n      options.handleChunk && options.handleChunk({ text: error.toString() });\n      resolve(error.toString());\n    });\n    request.write(JSON.stringify(body));\n    request.end();\n  });\n"
  },
  {
    "path": "share/LLM/openaiV2.ts",
    "content": "/* eslint-disable no-continue */\n/* eslint-disable no-shadow */\nimport * as https from 'https';\nimport * as http from 'http';\nimport { TextDecoder } from 'util';\nimport { oneAPIConfig } from '../utils/shareData';\n\nexport const createChatCompletion = (options: {\n  apiKey?: string;\n  hostname?: string;\n  apiPath?: string;\n  port?: number;\n  notHttps?: boolean;\n  model?: string;\n  maxTokens?: number;\n  messages: {\n    role: 'system' | 'user' | 'assistant';\n    content:\n      | string\n      | (\n          | {\n              type: 'image_url';\n              image_url: { url: string };\n            }\n          | { type: 'text'; text: string }\n        )[];\n  }[];\n  handleChunk?: (data: { text?: string }) => void;\n}) =>\n  new Promise<string>((resolve, reject) => {\n    const config = oneAPIConfig();\n    let combinedResult = '';\n    const error = '发生错误：';\n    const h = options.notHttps || config?.notHttps ? http : https;\n    const request = h.request(\n      {\n        hostname: options.hostname || config?.hostname || 'api.openai.com',\n        port: options.port || config?.port || 443,\n        path: options.apiPath || config?.apiPath || '/v1/chat/completions',\n        method: 'POST',\n        headers: {\n          'Content-Type': 'application/json',\n          Authorization: `Bearer ${options.apiKey || config?.apiKey}`,\n        },\n      },\n      (res) => {\n        let preDataLast = '';\n        res.on('data', async (chunk) => {\n          const text = new TextDecoder('utf-8').decode(chunk);\n          const data = text.split('\\n\\n').filter((s) => s);\n          for (let i = 0; i < data.length; i++) {\n            try {\n              let element = data[i];\n              if (i === data.length - 1 && !data[i].endsWith('}')) {\n                preDataLast = data[i];\n                continue;\n              }\n              if (element.startsWith('data: ')) {\n                if (element.trim() === 'data:') {\n                  // 处理只返回了 data: 的情况\n                  continue;\n                }\n              } else {\n                // 处理没有 data 开头\n                element = preDataLast + element;\n              }\n              if (element.includes('data: ')) {\n                if (element.includes('[DONE]')) {\n                  if (options.handleChunk) {\n                    options.handleChunk({ text: '' });\n                  }\n                  continue;\n                }\n                // remove 'data: '\n                const data = JSON.parse(element.replace('data: ', ''));\n                if (data.finish_reason === 'stop') {\n                  if (options.handleChunk) {\n                    options.handleChunk({ text: '' });\n                  }\n                  continue;\n                }\n                const openaiRes = data.choices[0].delta.content;\n                console.log(openaiRes);\n                if (openaiRes) {\n                  if (options.handleChunk) {\n                    options.handleChunk({\n                      text: openaiRes.replaceAll('\\\\n', '\\n'),\n                    });\n                  }\n                  combinedResult += openaiRes;\n                }\n              } else {\n                console.log('no includes data: ', element);\n              }\n            } catch (e) {\n              console.error({\n                e: (e as Error).toString(),\n                element: data[i],\n              });\n              // error = (e as Error).toString();\n            }\n          }\n        });\n        res.on('error', (e) => {\n          if (options.handleChunk) {\n            options.handleChunk({\n              text: e.toString(),\n            });\n          }\n          reject(e);\n        });\n        res.on('end', () => {\n          if (error !== '发生错误：') {\n            if (options.handleChunk) {\n              options.handleChunk({\n                text: error,\n              });\n            }\n          }\n          resolve(combinedResult || error);\n        });\n      },\n    );\n    const body = {\n      model: options.model || config?.model || 'gpt-3.5-turbo',\n      messages: options.messages,\n      stream: true,\n      max_tokens: options.maxTokens || config?.maxTokens || 2000,\n    };\n    request.on('error', (error) => {\n      // eslint-disable-next-line no-unused-expressions\n      options.handleChunk && options.handleChunk({ text: error.toString() });\n      resolve(error.toString());\n    });\n    request.write(JSON.stringify(body));\n    request.end();\n  });\n"
  },
  {
    "path": "share/TypeChatSlim/index.ts",
    "content": "import * as ts from 'typescript';\nimport { StatusBarAlignment, window } from 'vscode';\nimport { Success, Error, error, success } from './result';\n\nconst libText = `interface Array<T> { length: number, [n: number]: T }\ninterface Object { toString(): string }\ninterface Function { prototype: unknown }\ninterface CallableFunction extends Function {}\ninterface NewableFunction extends Function {}\ninterface String { readonly length: number }\ninterface Boolean { valueOf(): boolean }\ninterface Number { valueOf(): number }\ninterface RegExp { test(string: string): boolean }`;\n\nexport async function translate<T extends object>(option: {\n  schema: string;\n  typeName: string;\n  request: string;\n  createChatCompletion: (options: {\n    messages: {\n      role: 'system' | 'user' | 'assistant';\n      content: string;\n    }[];\n    handleChunk?: ((data: { text?: string }) => void) | undefined;\n    showWebview?: boolean;\n  }) => Promise<string>;\n  showWebview?: boolean;\n  /**\n   * @description 完整的 prompt，若提供则内部不再组合 prompt\n   * @type {string}\n   */\n  completePrompt?: string;\n  extendValidate?: (jsonObject: T) => Error | Success<T>;\n  /**\n   * @description 重试次数，默认为重试 3 次\n   * @type {number}\n   */\n  tryCount?: number;\n}) {\n  let requestPrompt =\n    option.completePrompt ||\n    `You are a service that translates user requests into JSON objects of type \"${option.typeName}\" according to the following TypeScript definitions:\\n` +\n      `\\`\\`\\`\\n${option.schema}\\`\\`\\`\\n` +\n      `The following is a user request:\\n` +\n      `\"\"\"\\n${option.request}\\n\"\"\"\\n` +\n      `The following is the user request translated into a JSON object with 2 spaces of indentation and no properties with the value undefined:\\n`;\n  let tryCount = 1;\n  // eslint-disable-next-line no-unreachable-loop, no-constant-condition\n  while (true) {\n    // eslint-disable-next-line no-await-in-loop\n    let responseText = await option.createChatCompletion({\n      messages: [{ role: 'user', content: requestPrompt }],\n      handleChunk: undefined,\n      showWebview: option.showWebview,\n    });\n\n    let match = /```json([\\s\\S]*?)```/g.exec(responseText);\n    if (match && match[1]) {\n      // eslint-disable-next-line prefer-destructuring\n      responseText = match[1];\n    } else {\n      match = /```([\\s\\S]*?)```/g.exec(responseText);\n    }\n    if (match && match[1]) {\n      // eslint-disable-next-line prefer-destructuring\n      responseText = match[1];\n    }\n    let validation = validate<T>(\n      responseText.replace(/```json/g, '').replace(/```/g, ''),\n      option.schema,\n      option.typeName,\n    );\n    if (validation.success) {\n      // 走额外的校验\n      if (option.extendValidate) {\n        validation = option.extendValidate(validation.data);\n        if (validation.success) {\n          return validation;\n        }\n      } else {\n        return validation;\n      }\n    }\n    if (tryCount > (option.tryCount || 3)) {\n      return validation;\n    }\n    requestPrompt += `${responseText}\\n${createRepairPrompt(\n      validation.message,\n    )}`;\n    tryCount++;\n  }\n}\n\nfunction createRepairPrompt(validationError: string) {\n  return (\n    `The JSON object is invalid for the following reason:\\n` +\n    `\"\"\"\\n${validationError}\\n\"\"\"\\n` +\n    `The following is a revised JSON object:\\n`\n  );\n}\n\nexport function validate<T extends object>(\n  jsonText: string,\n  schema: string,\n  typeName: string,\n) {\n  let jsonObject;\n  try {\n    let match = /```json([\\s\\S]*?)```/g.exec(jsonText);\n    if (match && match[1]) {\n      // eslint-disable-next-line prefer-destructuring\n      jsonText = match[1];\n    } else {\n      match = /```([\\s\\S]*?)```/g.exec(jsonText);\n    }\n    if (match && match[1]) {\n      // eslint-disable-next-line prefer-destructuring\n      jsonText = match[1];\n    }\n    jsonObject = JSON.parse(\n      jsonText.replace(/```json/g, '').replace(/```/g, ''),\n    ) as object;\n  } catch (e) {\n    return error(e instanceof SyntaxError ? e.message : 'JSON parse error');\n  }\n  stripNulls(jsonObject);\n  const moduleResult = `import { ${typeName} } from './schema';\\nconst json: ${typeName} = ${JSON.stringify(\n    jsonObject,\n    undefined,\n    2,\n  )};\\n`;\n\n  const program = createProgramFromModuleText({\n    moduleText: moduleResult,\n    schema,\n  });\n  const syntacticDiagnostics = program.getSyntacticDiagnostics();\n  const programDiagnostics = syntacticDiagnostics.length\n    ? syntacticDiagnostics\n    : program.getSemanticDiagnostics();\n  if (programDiagnostics.length) {\n    const diagnostics = programDiagnostics\n      .map((d) =>\n        typeof d.messageText === 'string'\n          ? d.messageText\n          : d.messageText.messageText,\n      )\n      .join('\\n');\n    return error(diagnostics);\n  }\n  return success<T>(jsonObject);\n}\n\nfunction createProgramFromModuleText(option: {\n  moduleText: string;\n  oldProgram?: ts.Program;\n  schema: string;\n}) {\n  const fileMap = new Map([\n    createFileMapEntry('/lib.d.ts', libText),\n    createFileMapEntry('/schema.ts', option.schema),\n    createFileMapEntry('/json.ts', option.moduleText),\n  ]);\n\n  const host: ts.CompilerHost = {\n    getSourceFile: (fileName) => fileMap.get(fileName),\n    getDefaultLibFileName: () => 'lib.d.ts',\n    writeFile: () => {},\n    getCurrentDirectory: () => '/',\n    getCanonicalFileName: (fileName) => fileName,\n    useCaseSensitiveFileNames: () => true,\n    getNewLine: () => '\\n',\n    fileExists: (fileName) => fileMap.has(fileName),\n    readFile: (fileName) => '',\n  };\n  const options: ts.CompilerOptions = {\n    ...ts.getDefaultCompilerOptions(),\n    strict: true,\n    skipLibCheck: true,\n    noLib: true,\n    types: [],\n  };\n  return ts.createProgram(\n    Array.from(fileMap.keys()),\n    options,\n    host,\n    option.oldProgram,\n  );\n}\n\nfunction createFileMapEntry(\n  filePath: string,\n  fileText: string,\n): [string, ts.SourceFile] {\n  return [\n    filePath,\n    ts.createSourceFile(filePath, fileText, ts.ScriptTarget.Latest),\n  ];\n}\n\nfunction stripNulls(obj: any) {\n  let keysToDelete: string[] | undefined;\n  // eslint-disable-next-line no-restricted-syntax, guard-for-in\n  for (const k in obj) {\n    const value = obj[k];\n    if (value === null) {\n      (keysToDelete ??= []).push(k);\n    } else {\n      if (Array.isArray(value)) {\n        if (value.some((x) => x === null)) {\n          obj[k] = value.filter((x) => x !== null);\n        }\n      }\n      if (typeof value === 'object') {\n        stripNulls(value);\n      }\n    }\n  }\n  if (keysToDelete) {\n    // eslint-disable-next-line no-restricted-syntax\n    for (const k of keysToDelete) {\n      delete obj[k];\n    }\n  }\n}\n"
  },
  {
    "path": "share/TypeChatSlim/result.ts",
    "content": "export type Success<T> = { success: true; data: T };\n\nexport type Error = { success: false; message: string };\n\nexport type Result<T> = Success<T> | Error;\n\nexport function success<T>(data: T): Success<T> {\n  return { success: true, data };\n}\n\nexport function error(message: string): Error {\n  return { success: false, message };\n}\n\nexport function getData<T>(result: Result<T>) {\n  if (result.success) {\n    return result.data;\n  }\n  throw new Error(result.message);\n}\n"
  },
  {
    "path": "share/TypeChatSlim/utools.ts",
    "content": "import * as ts from 'typescript';\nimport { Success, Error, error, success } from './result';\n\nconst libText = `interface Array<T> { length: number, [n: number]: T }\ninterface Object { toString(): string }\ninterface Function { prototype: unknown }\ninterface CallableFunction extends Function {}\ninterface NewableFunction extends Function {}\ninterface String { readonly length: number }\ninterface Boolean { valueOf(): boolean }\ninterface Number { valueOf(): number }\ninterface RegExp { test(string: string): boolean }`;\n\nexport async function translate<T extends object>(option: {\n  schema: string;\n  typeName: string;\n  request: string;\n  createChatCompletion: (options: {\n    messages: {\n      role: 'system' | 'user' | 'assistant';\n      content: string;\n    }[];\n    handleChunk?: ((data: { text?: string }) => void) | undefined;\n  }) => Promise<string>;\n  showWebview?: boolean;\n  scriptFile: string;\n  /**\n   * @description 完整的 prompt，若提供则内部不再组合 prompt\n   * @type {string}\n   */\n  completePrompt?: string;\n  extendValidate?: (jsonObject: T) => Error | Success<T>;\n  /**\n   * @description 重试次数，默认为重试 3 次\n   * @type {number}\n   */\n  tryCount?: number;\n}) {\n  let requestPrompt =\n    option.completePrompt ||\n    `You are a service that translates user requests into JSON objects of type \"${option.typeName}\" according to the following TypeScript definitions:\\n` +\n      `\\`\\`\\`\\n${option.schema}\\`\\`\\`\\n` +\n      `The following is a user request:\\n` +\n      `\"\"\"\\n${option.request}\\n\"\"\"\\n` +\n      `The following is the user request translated into a JSON object with 2 spaces of indentation and no properties with the value undefined:\\n`;\n  let tryCount = 1;\n  // eslint-disable-next-line no-unreachable-loop, no-constant-condition\n  while (true) {\n    // eslint-disable-next-line no-await-in-loop\n    const responseText = await option\n      .createChatCompletion({\n        messages: [{ role: 'user', content: requestPrompt }],\n        handleChunk: undefined,\n      })\n      .finally(() => {});\n    let validation = validate<T>(responseText, option.schema, option.typeName);\n    if (validation.success) {\n      // 走额外的校验\n      if (option.extendValidate) {\n        validation = option.extendValidate(validation.data);\n        if (validation.success) {\n          return { ...validation, responseText };\n        }\n      } else {\n        return { ...validation, responseText };\n      }\n    }\n\n    requestPrompt += `${responseText}\\n${createRepairPrompt(\n      validation.message,\n    )}`;\n    if (option.showWebview) {\n      // eslint-disable-next-line no-loop-func\n      // setTimeout(() => {\n      //   utools.redirect(['lowcode', 'lowcode'], {\n      //     type: 'text',\n      //     data: JSON.stringify({\n      //       scriptFile: option.scriptFile,\n      //       route: '/chat',\n      //       content: requestPrompt,\n      //     }),\n      //   });\n      // }, 1000);\n      return { ...validation, responseText };\n    }\n    if (tryCount > (option.tryCount || 3)) {\n      return { ...validation, responseText };\n    }\n\n    tryCount++;\n  }\n}\n\nfunction createRepairPrompt(validationError: string) {\n  return (\n    `The JSON object is invalid for the following reason:\\n` +\n    `\"\"\"\\n${validationError}\\n\"\"\"\\n` +\n    `The following is a revised JSON object:\\n`\n  );\n}\n\nexport function validate<T extends object>(\n  jsonText: string,\n  schema: string,\n  typeName: string,\n) {\n  let jsonObject;\n  try {\n    let match = /```json([\\s\\S]*?)```/g.exec(jsonText);\n    if (match && match[1]) {\n      // eslint-disable-next-line prefer-destructuring\n      jsonText = match[1];\n    } else {\n      match = /```([\\s\\S]*?)```/g.exec(jsonText);\n    }\n    if (match && match[1]) {\n      // eslint-disable-next-line prefer-destructuring\n      jsonText = match[1];\n    }\n    jsonObject = JSON.parse(\n      jsonText.replace(/```json/g, '').replace(/```/g, ''),\n    ) as object;\n  } catch (e) {\n    return error(e instanceof SyntaxError ? e.message : 'JSON parse error');\n  }\n  stripNulls(jsonObject);\n  const moduleResult = `import { ${typeName} } from './schema';\\nconst json: ${typeName} = ${JSON.stringify(\n    jsonObject,\n    undefined,\n    2,\n  )};\\n`;\n\n  const program = createProgramFromModuleText({\n    moduleText: moduleResult,\n    schema,\n  });\n  const syntacticDiagnostics = program.getSyntacticDiagnostics();\n  const programDiagnostics = syntacticDiagnostics.length\n    ? syntacticDiagnostics\n    : program.getSemanticDiagnostics();\n  if (programDiagnostics.length) {\n    const diagnostics = programDiagnostics\n      .map((d) =>\n        typeof d.messageText === 'string'\n          ? d.messageText\n          : d.messageText.messageText,\n      )\n      .join('\\n');\n    return error(diagnostics);\n  }\n  return success<T>(jsonObject);\n}\n\nfunction createProgramFromModuleText(option: {\n  moduleText: string;\n  oldProgram?: ts.Program;\n  schema: string;\n}) {\n  const fileMap = new Map([\n    createFileMapEntry('/lib.d.ts', libText),\n    createFileMapEntry('/schema.ts', option.schema),\n    createFileMapEntry('/json.ts', option.moduleText),\n  ]);\n\n  const host: ts.CompilerHost = {\n    getSourceFile: (fileName) => fileMap.get(fileName),\n    getDefaultLibFileName: () => 'lib.d.ts',\n    writeFile: () => {},\n    getCurrentDirectory: () => '/',\n    getCanonicalFileName: (fileName) => fileName,\n    useCaseSensitiveFileNames: () => true,\n    getNewLine: () => '\\n',\n    fileExists: (fileName) => fileMap.has(fileName),\n    readFile: (fileName) => '',\n  };\n  const options: ts.CompilerOptions = {\n    ...ts.getDefaultCompilerOptions(),\n    strict: true,\n    skipLibCheck: true,\n    noLib: true,\n    types: [],\n  };\n  return ts.createProgram(\n    Array.from(fileMap.keys()),\n    options,\n    host,\n    option.oldProgram,\n  );\n}\n\nfunction createFileMapEntry(\n  filePath: string,\n  fileText: string,\n): [string, ts.SourceFile] {\n  return [\n    filePath,\n    ts.createSourceFile(filePath, fileText, ts.ScriptTarget.Latest),\n  ];\n}\n\nfunction stripNulls(obj: any) {\n  let keysToDelete: string[] | undefined;\n  // eslint-disable-next-line no-restricted-syntax, guard-for-in\n  for (const k in obj) {\n    const value = obj[k];\n    if (value === null) {\n      (keysToDelete ??= []).push(k);\n    } else {\n      if (Array.isArray(value)) {\n        if (value.some((x) => x === null)) {\n          obj[k] = value.filter((x) => x !== null);\n        }\n      }\n      if (typeof value === 'object') {\n        stripNulls(value);\n      }\n    }\n  }\n  if (keysToDelete) {\n    // eslint-disable-next-line no-restricted-syntax\n    for (const k of keysToDelete) {\n      delete obj[k];\n    }\n  }\n}\n"
  },
  {
    "path": "share/WebView/callback.ts",
    "content": "import * as vscode from 'vscode';\n\nexport function invokeCallback<T = any>(\n  webview: vscode.Webview,\n  cbid: string,\n  res: T,\n) {\n  webview.postMessage({\n    cmd: 'vscodeCallback',\n    cbid,\n    data: res,\n    code: 200,\n  });\n}\n\nexport function invokeLLMChunkCallback<T = any>(\n  webview: vscode.Webview,\n  cbid: string,\n  res: T,\n) {\n  webview.postMessage({\n    cmd: 'vscodeLLMChunkCallback',\n    task: 'handleLLMChunk',\n    cbid,\n    data: res,\n    code: 200,\n  });\n}\n\nexport function invokeErrorCallback(\n  webview: vscode.Webview,\n  cbid: string,\n  res: any,\n) {\n  webview.postMessage({\n    cmd: 'vscodeCallback',\n    cbid,\n    data: res,\n    code: 400,\n  });\n}\n"
  },
  {
    "path": "share/WebView/controllers/alert.ts",
    "content": "import { window } from 'vscode';\nimport { IMessage } from '../type';\n\nconst alert = {\n  alert: (message: IMessage<string>) => {\n    window.showErrorMessage(message.data);\n    return '来自vscode的响应';\n  },\n};\n\nexport default alert;\n"
  },
  {
    "path": "share/WebView/controllers/dynamicForm.ts",
    "content": "import * as vscode from 'vscode';\nimport { CompileContext } from 'lowcode-context';\nimport { IMessage } from '../type';\nimport { getDynamicFormConfig } from '../../../share/utils/dynamicForm';\n\nexport const getDynamicForm = (\n  message: IMessage,\n  context: {\n    webview: vscode.Webview;\n    task: { task: string; data?: any };\n  } & CompileContext,\n) => {\n  const { materialPath } = context;\n  const config = getDynamicFormConfig({ vscodeMaterialPath: materialPath });\n  return {\n    schema: config.schema,\n    scripts: config.scripts,\n  };\n};\n"
  },
  {
    "path": "share/WebView/controllers/llm.ts",
    "content": "import * as vscode from 'vscode';\nimport { CompileContext } from 'lowcode-context';\nimport { createChatCompletion } from '../../LLM';\nimport { IMessage } from '../type';\nimport { invokeLLMChunkCallback } from '../callback';\n\ntype LLMMessage = (\n  | {\n      role: 'system';\n      content: string;\n    }\n  | {\n      role: 'user';\n      content:\n        | string\n        | (\n            | {\n                type: 'image_url';\n                image_url: { url: string };\n              }\n            | { type: 'text'; text: string }\n          )[];\n    }\n)[];\n\nexport const askLLM = async (\n  message: IMessage<{ messages: LLMMessage; llm?: 'gemini' | 'geminiProxy' }>,\n  lowcodeContext: {\n    webview: vscode.Webview;\n  } & CompileContext,\n) => {\n  const res = await createChatCompletion({\n    messages: message.data.messages,\n    lowcodeContext,\n    handleChunk(data) {\n      invokeLLMChunkCallback(lowcodeContext.webview, message.cbid, {\n        content: data.text,\n      });\n    },\n    llm: message.data.llm,\n  });\n\n  return {\n    content: res,\n  };\n};\n"
  },
  {
    "path": "share/WebView/controllers/script.ts",
    "content": "/* eslint-disable no-eval */\nimport * as path from 'path';\nimport * as vscode from 'vscode';\nimport * as fs from 'fs-extra';\nimport { CompileContext } from 'lowcode-context';\nimport { IMessage } from '../type';\n\nexport const runScript = async (\n  message: IMessage<{\n    materialPath: string;\n    script: string;\n    params: string;\n  }>,\n  context: {\n    webview: vscode.Webview;\n    task: { task: string; data?: any };\n  } & CompileContext,\n) => {\n  const scriptFile = path.join(message.data.materialPath, 'script/index.js');\n  if (fs.existsSync(scriptFile)) {\n    delete eval('require').cache[eval('require').resolve(scriptFile)];\n    const script = eval('require')(scriptFile);\n    if (script[message.data.script]) {\n      const c = {\n        ...context,\n        params: message.data.params,\n        materialPath: message.data.materialPath,\n      };\n      const scriptRes = await script[message.data.script](c);\n      return scriptRes;\n    }\n    throw new Error(`方法: ${message.data.script} 不存在`);\n  } else {\n    throw new Error(`脚本文件不存在`);\n  }\n};\n"
  },
  {
    "path": "share/WebView/controllers/task.ts",
    "content": "import * as vscode from 'vscode';\nimport { IMessage } from '../type';\n\nexport const getTask = async (\n  message: IMessage,\n  context: {\n    webview: vscode.Webview;\n    task: { task: string; data?: any };\n  },\n) => context.task;\n"
  },
  {
    "path": "share/WebView/index.ts",
    "content": "/* eslint-disable no-underscore-dangle */\nimport * as vscode from 'vscode';\nimport { window } from 'vscode';\nimport type { CompileContext } from 'lowcode-context';\nimport { routes } from './routes';\nimport { invokeCallback, invokeErrorCallback } from './callback';\n\ntype WebViewKeys = 'main' | string;\n\nlet webviewPanels: {\n  key: WebViewKeys;\n  panel: vscode.WebviewPanel;\n  disposables: vscode.Disposable[];\n}[] = [];\n\nconst getHtmlForWebview = (dev = false) => {\n  if (dev) {\n    return `\n\t\t<!doctype html>\n\t\t<html lang=\"en\">\n\t\t\t<head>\n\t\t\t\t<script type=\"module\">import { injectIntoGlobalHook } from \"http://127.0.0.1:5173/@react-refresh\";\n\t\t\t\tinjectIntoGlobalHook(window);\n\t\t\t\twindow.$RefreshReg$ = () => {};\n\t\t\t\twindow.$RefreshSig$ = () => (type) => type;</script>\n\n\t\t\t\t<script type=\"module\" src=\"http://127.0.0.1:5173/@vite/client\"></script>\n\t\t\t\t<script>\n\t\t\t\t   window.vscode = acquireVsCodeApi();\n        </script>\n\t\t\t\t<meta charset=\"UTF-8\" />\n\t\t\t\t<link rel=\"icon\" type=\"image/svg+xml\" href=\"http://127.0.0.1:5173/vite.svg\" />\n\t\t\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n\t\t\t\t<title>Vite + React + TS</title>\n\t\t\t</head>\n\t\t\t<body>\n\t\t\t\t<div id=\"root\"></div>\n\t\t\t\t<script type=\"module\" src=\"http://127.0.0.1:5173/src/main.tsx\"></script>\n\t\t\t</body>\n\t\t</html>\n\t\t`;\n  }\n  return `\n\t\t\t<!DOCTYPE html>\n\t\t\t<html>\n\t\t\t<head>\n\t\t\t\t<meta charset=\"utf-8\" />\n\t\t\t\t<meta\n\t\t\t\t\tname=\"viewport\"\n\t\t\t\t\tcontent=\"width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no\"\n\t\t\t\t/>\n        <style>\n          .loader {\n            position: fixed;\n            top: 50%;\n            left: 50%;\n            width: 160px;\n            height: 160px;\n            margin: -80px 0px 0px -80px;\n            background-color: transparent;\n            border-radius: 50%;\n            border: 2px solid #e3e4dc;\n          }\n\n          .loader:before {\n            content: '';\n            width: 164px;\n            height: 164px;\n            display: block;\n            position: absolute;\n            border: 2px solid #898a86;\n            border-radius: 50%;\n            top: -2px;\n            left: -2px;\n            box-sizing: border-box;\n            clip: rect(0px, 35px, 35px, 0px);\n            z-index: 10;\n            animation: rotate infinite;\n            animation-duration: 3s;\n            animation-timing-function: linear;\n          }\n\n          .loader:after {\n            content: '';\n            width: 164px;\n            height: 164px;\n            display: block;\n            position: absolute;\n            border: 2px solid #c1bebb;\n            border-radius: 50%;\n            top: -2px;\n            left: -2px;\n            box-sizing: border-box;\n            clip: rect(0px, 164px, 150px, 0px);\n            z-index: 9;\n            animation: rotate2 3s linear infinite;\n          }\n\n          .hexagon-container {\n            position: relative;\n            top: 33px;\n            left: 41px;\n            border-radius: 50%;\n            margin: 0px;\n            padding: 0px;\n          }\n\n          .hexagon-container li {\n            list-style: none;\n          }\n\n          .hexagon {\n            position: absolute;\n            width: 40px;\n            height: 23px;\n            background-color: #556c82;\n          }\n\n          .hexagon:before {\n            content: '';\n            position: absolute;\n            top: -11px;\n            left: 0;\n            width: 0;\n            height: 0;\n            border-left: 20px solid transparent;\n            border-right: 20px solid transparent;\n            border-bottom: 11.5px solid #556c82;\n          }\n\n          .hexagon:after {\n            content: '';\n            position: absolute;\n            top: 23px;\n            left: 0;\n            width: 0;\n            height: 0;\n            border-left: 20px solid transparent;\n            border-right: 20px solid transparent;\n            border-top: 11.5px solid #556c82;\n          }\n\n          .hexagon.hex_1 {\n            top: 0px;\n            left: 0px;\n            animation: Animasearch 3s ease-in-out infinite;\n            animation-delay: 0.2142857143s;\n          }\n\n          .hexagon.hex_2 {\n            top: 0px;\n            left: 42px;\n            animation: Animasearch 3s ease-in-out infinite;\n            animation-delay: 0.4285714286s;\n          }\n\n          .hexagon.hex_3 {\n            top: 36px;\n            left: 63px;\n            animation: Animasearch 3s ease-in-out infinite;\n            animation-delay: 0.6428571429s;\n          }\n\n          .hexagon.hex_4 {\n            top: 72px;\n            left: 42px;\n            animation: Animasearch 3s ease-in-out infinite;\n            animation-delay: 0.8571428571s;\n          }\n\n          .hexagon.hex_5 {\n            top: 72px;\n            left: 0px;\n            animation: Animasearch 3s ease-in-out infinite;\n            animation-delay: 1.0714285714s;\n          }\n\n          .hexagon.hex_6 {\n            top: 36px;\n            left: -21px;\n            animation: Animasearch 3s ease-in-out infinite;\n            animation-delay: 1.2857142857s;\n          }\n\n          .hexagon.hex_7 {\n            top: 36px;\n            left: 21px;\n            animation: Animasearch 3s ease-in-out infinite;\n            animation-delay: 1.5s;\n          }\n\n          @keyframes Animasearch {\n            0% {\n              transform: scale(1);\n              opacity: 1;\n            }\n            15%,\n            50% {\n              transform: scale(0.5);\n              opacity: 0;\n            }\n            65% {\n              transform: scale(1);\n              opacity: 1;\n            }\n          }\n\n          @keyframes rotate {\n            0% {\n              transform: rotate(0);\n              clip: rect(0px, 35px, 35px, 0px);\n            }\n            50% {\n              clip: rect(0px, 40px, 40px, 0px);\n            }\n            100% {\n              transform: rotate(360deg);\n              clip: rect(0px, 35px, 35px, 0px);\n            }\n          }\n\n          @keyframes rotate2 {\n            0% {\n              transform: rotate(0deg);\n              clip: rect(0px, 164px, 150px, 0px);\n            }\n            50% {\n              clip: rect(0px, 164px, 0px, 0px);\n              transform: rotate(360deg);\n            }\n            100% {\n              transform: rotate(720deg);\n              clip: rect(0px, 164px, 150px, 0px);\n            }\n          }\n\n          @keyframes rotate3 {\n            0% {\n              transform: rotate(0deg);\n            }\n            100% {\n              transform: rotate(360deg);\n            }\n          }\n        </style>\n\t\t\t\t<script>\n\t\t\t\t   window.vscode = acquireVsCodeApi();\n        </script>\n\t\t\t\t<script type=\"module\" crossorigin src=\"http://lowcode-utools.oss-cn-beijing.aliyuncs.com/vscode.index.js\"></script>\n\t\t\t\t<link rel=\"stylesheet\" crossorigin href=\"http://lowcode-utools.oss-cn-beijing.aliyuncs.com/vscode.index.css\">\n\t\t\t</head>\n\t\t\t<body>\n        <div id=\"StartLoading\" class=\"loader\">\n          <ul class=\"hexagon-container\">\n            <li class=\"hexagon hex_1\"></li>\n            <li class=\"hexagon hex_2\"></li>\n            <li class=\"hexagon hex_3\"></li>\n            <li class=\"hexagon hex_4\"></li>\n            <li class=\"hexagon hex_5\"></li>\n            <li class=\"hexagon hex_6\"></li>\n            <li class=\"hexagon hex_7\"></li>\n          </ul>\n        </div>\n\t\t\t\t<div id=\"root\"></div>\n\t\t\t</body>\n\t\t</html>\n`;\n};\n\nexport const showWebView = (options: {\n  key: WebViewKeys;\n  lowcodeContext: CompileContext;\n  title?: string;\n  viewColumn?: vscode.ViewColumn;\n  /**\n   * webview 打开后执行命令，比如转到指定路由\n   */\n  task?: { task: string; data?: any };\n  htmlForWebview?: string;\n  routes?: Record<string, any>;\n}) => {\n  const webview = webviewPanels.find((s) => s.key === options.key);\n  if (webview) {\n    webview.panel.reveal();\n    if (options.task) {\n      webview.panel.webview.postMessage({\n        cmd: 'vscodePushTask',\n        task: options.task.task,\n        data: options.task.data,\n      });\n    }\n  } else {\n    // 创建 webview 的时候，设置之前 focus 的 activeTextEditor\n    // if (vscode.window.activeTextEditor) {\n    //   setLastActiveTextEditorId((vscode.window.activeTextEditor as any).id);\n    // }\n    const panel = vscode.window.createWebviewPanel(\n      'lowcode',\n      options.title || 'LOW-CODE可视化',\n      {\n        viewColumn: options.viewColumn || vscode.ViewColumn.Two,\n        preserveFocus: true,\n      },\n      {\n        enableScripts: true,\n        // localResourceRoots: [\n        //   vscode.Uri.file(path.join(getExtensionPath(), 'webview-dist')),\n        // ],\n        retainContextWhenHidden: true, // webview被隐藏时保持状态，避免被重置\n      },\n    );\n    // panel.iconPath = vscode.Uri.file(\n    //   path.join(getExtensionPath(), 'asset', 'icon.png'),\n    // );\n    panel.webview.html = options.htmlForWebview\n      ? options.htmlForWebview\n      : getHtmlForWebview();\n    const disposables: vscode.Disposable[] = [];\n    panel.webview.onDidReceiveMessage(\n      async (message: {\n        cmd: string;\n        cbid: string;\n        data: any;\n        skipError?: boolean;\n      }) => {\n        if (options.routes && options.routes[message.cmd]) {\n          try {\n            const res = await options.routes[message.cmd](message, {\n              webview: panel.webview,\n              webviewKey: options.key,\n              task: options.task,\n              ...options.lowcodeContext,\n            });\n            invokeCallback(panel.webview, message.cbid, res);\n          } catch (ex: any) {\n            if (!message.skipError) {\n              window.showErrorMessage(ex.toString());\n            }\n            invokeErrorCallback(panel.webview, message.cbid, ex);\n          }\n        } else if (routes[message.cmd]) {\n          try {\n            const res = await routes[message.cmd](message, {\n              webview: panel.webview,\n              webviewKey: options.key,\n              task: options.task,\n              ...options.lowcodeContext,\n            });\n            invokeCallback(panel.webview, message.cbid, res);\n          } catch (ex: any) {\n            if (!message.skipError) {\n              window.showErrorMessage(ex.toString());\n            }\n            invokeErrorCallback(panel.webview, message.cbid, ex);\n          }\n        } else {\n          invokeErrorCallback(\n            panel.webview,\n            message.cbid,\n            `未找到名为 ${message.cmd} 回调方法!`,\n          );\n          vscode.window.showWarningMessage(\n            `未找到名为 ${message.cmd} 回调方法!`,\n          );\n        }\n      },\n      null,\n      disposables,\n    );\n    panel.onDidDispose(\n      () => {\n        panel.dispose();\n        while (disposables.length) {\n          const x = disposables.pop();\n          if (x) {\n            x.dispose();\n          }\n        }\n        webviewPanels = webviewPanels.filter((s) => s.key !== options.key);\n      },\n      null,\n      disposables,\n    );\n    webviewPanels.push({\n      key: options.key,\n      panel,\n      disposables,\n    });\n    if (options.task) {\n      setTimeout(() => {\n        panel.webview.postMessage({\n          cmd: 'vscodePushTask',\n          task: options.task!.task,\n          data: options.task!.data,\n        });\n      }, 500);\n    }\n  }\n};\n\nexport const closeWebView = (key: WebViewKeys) => {\n  const webviewPanel = webviewPanels.find((s) => s.key === key);\n  webviewPanel?.panel.dispose();\n  webviewPanels = webviewPanels.filter((s) => s.key !== key);\n};\n"
  },
  {
    "path": "share/WebView/routes/index.ts",
    "content": "import alert from '../controllers/alert';\nimport * as task from '../controllers/task';\nimport * as script from '../controllers/script';\nimport * as llm from '../controllers/llm';\nimport * as dynamicForm from '../controllers/dynamicForm';\n\nexport const routes: Record<string, any> = {\n  alert: alert.alert,\n  getTask: task.getTask,\n  runScript: script.runScript,\n  askLLM: llm.askLLM,\n  getDynamicForm: dynamicForm.getDynamicForm,\n};\n"
  },
  {
    "path": "share/WebView/type.ts",
    "content": "export interface IMessage<T = any> {\n  cmd: string;\n  cbid: string;\n  data: T;\n}\n"
  },
  {
    "path": "share/clearCache.ts",
    "content": "import fs from 'fs-extra';\n\nexport const clearCache = (path: string, clearShare = true) => {\n  getAllFiles(path).forEach((file) => {\n    if (!file.includes('script/index.js')) {\n      delete require.cache[require.resolve(file)];\n    }\n  });\n  if (clearShare) {\n    getAllFiles(__dirname).forEach((file) => {\n      if (!file.includes('clearCache')) {\n        delete require.cache[require.resolve(file)];\n      }\n    });\n  }\n};\n\n// 递归获取文件夹下的所有文件\nfunction getAllFiles(dirPath: string) {\n  const files = fs.readdirSync(dirPath);\n\n  let result: string[] = [];\n\n  // eslint-disable-next-line no-restricted-syntax\n  for (const file of files) {\n    const filePath = `${dirPath}/${file}`;\n    // eslint-disable-next-line no-await-in-loop\n    const stats = fs.statSync(filePath);\n\n    if (stats.isDirectory()) {\n      result = result.concat(getAllFiles(filePath));\n    } else {\n      result.push(filePath);\n    }\n  }\n\n  return result;\n}\n"
  },
  {
    "path": "share/uTools/webviewBaseController.ts",
    "content": "import { validate } from '@share/TypeChatSlim/utools';\nimport { getDynamicFormConfig } from '@share/utils/dynamicForm';\nimport {\n  askChatGPT as askOpenai,\n  getBlockJsonValidSchema,\n} from '@share/utils/uTools';\n\nexport type MethodHandle = (data: {\n  method: string;\n  params: string;\n  model: object;\n  scriptFile: string;\n}) => Promise<{\n  /** 立即更新 model */\n  updateModelImmediately?: boolean;\n  /** 仅更新参数 */\n  onlyUpdateParams?: boolean;\n  /** 要更新的参数 */\n  params?: string;\n  /** 打开 LLM Chat，DynamicForm Page使用 */\n  showChat?: boolean;\n  /** 关闭表单界面, Chat Page 使用 */\n  closeForm?: boolean;\n  /** LLM Chat Content */\n  chatContent?: string;\n  model: object;\n}>;\n\n// #region 获取动态表单配置\n\ntype GetDynamicForm = (data: { scriptFile: string }) => Promise<{\n  schema: object;\n  scripts: { method: string; remark: string }[];\n}>;\n\nexport const getDynamicForm: GetDynamicForm = (data) => {\n  const config = getDynamicFormConfig({ utoolsScriptFile: data.scriptFile });\n  return Promise.resolve({\n    schema: config.schema,\n    scripts: config.scripts,\n  });\n};\n\n// #endregion\n\nexport type LLMMessage = (\n  | {\n      role: 'system';\n      content: string;\n    }\n  | {\n      role: 'user';\n      content:\n        | string\n        | (\n            | {\n                type: 'image_url';\n                image_url: { url: string };\n              }\n            | { type: 'text'; text: string }\n          )[];\n    }\n)[];\n\n// #region 动态表单页面 LLM 交互\n\nexport type AskChatGPTForDynamicFormPageWebviewData = {\n  params: string;\n  model: object;\n  scriptFile: string;\n  messages: LLMMessage;\n  handleChunk: (chunck: string) => void;\n};\ntype AskChatGPTForDynamicFormPage = (\n  data: AskChatGPTForDynamicFormPageWebviewData & {\n    /** 用于校验 json 数据的 TS 类型名称 */\n    validateJsonSchemaTypeName?: string;\n  },\n) => Promise<{\n  /** LLM 返回内容 */\n  content: string;\n  /** 立即更新 model */\n  updateModelImmediately: boolean;\n  /** 仅更新参数 */\n  onlyUpdateParams: boolean;\n  /** 要更新的参数 */\n  params?: string;\n  /** 关闭 LLM Chat */\n  closeChat?: boolean;\n  model: object;\n}>;\n\nexport const baseAskChatGPTForDynamicFormPage: AskChatGPTForDynamicFormPage =\n  async (data) => {\n    const res = await askOpenai({\n      messages: data.messages,\n      handleChunk: data.handleChunk,\n    });\n    if (!data.validateJsonSchemaTypeName) {\n      return {\n        content: res.content,\n        updateModelImmediately: false,\n        onlyUpdateParams: true,\n        params: data.params,\n        closeChat: false,\n        model: data.model,\n      };\n    }\n    const valid = validate(\n      res.content,\n      getBlockJsonValidSchema(data.scriptFile),\n      data.validateJsonSchemaTypeName,\n    );\n    if (valid.success) {\n      return {\n        content: res.content,\n        updateModelImmediately: false,\n        onlyUpdateParams: false,\n        params: data.params,\n        closeChat: true,\n        model: valid.data,\n      };\n    }\n    data.handleChunk(`\n\n${valid.message}`);\n\n    return {\n      content: res.content,\n      updateModelImmediately: false,\n      onlyUpdateParams: true,\n      params: valid.message,\n      closeChat: false,\n      model: data.model,\n    };\n  };\n\n// #endregion\n\n// #region 处理页面 ChatGPT 请求\nexport type AskChatGPTData = {\n  params: string;\n  model: object;\n  scriptFile: string;\n  messages: LLMMessage;\n  handleChunk: (chunck: string) => void;\n};\n\nexport type AskChatGPT = (\n  data: AskChatGPTData & {\n    /** 用于校验 json 数据的 TS 类型名称 */\n    validateJsonSchemaTypeName?: string;\n  },\n) => Promise<{\n  /** LLM 返回内容 */\n  content: string;\n  /** 立即更新 model */\n  updateModelImmediately?: boolean;\n  /** 仅更新参数 */\n  onlyUpdateParams?: boolean;\n  /** 要更新的参数 */\n  params?: string;\n  /** 打开表单界面, Chat Page 使用 */\n  showForm?: boolean;\n  /** 表单数据 */\n  model?: object;\n}>;\nexport const askChatGPT: AskChatGPT = (data: {\n  messages: LLMMessage;\n  handleChunk: (chunck: string) => void;\n  model?: object;\n}) => askOpenai({ ...data, model: undefined });\n// #endregion\n"
  },
  {
    "path": "share/utils/clipboardImage.ts",
    "content": "import * as path from 'path';\nimport { spawn } from 'child_process';\nimport { homedir } from 'os';\nimport * as fs from 'fs-extra';\n\nconst saveClipboardImageToPath = (projectPath: string, imagePath: string) => {\n  return new Promise<string>((resolve, reject) => {\n    const { platform } = process;\n    if (platform === 'win32') {\n      // Windows\n      const scriptPath = path.join(\n        projectPath,\n        '/scripts/ClipboardImage/pc.ps1',\n      );\n\n      let command =\n        'C:\\\\Windows\\\\System32\\\\WindowsPowerShell\\\\v1.0\\\\powershell.exe';\n      const powershellExisted = fs.existsSync(command);\n      if (!powershellExisted) {\n        command = 'powershell';\n      }\n\n      const powershell = spawn(command, [\n        '-noprofile',\n        '-noninteractive',\n        '-nologo',\n        '-sta',\n        '-executionpolicy',\n        'unrestricted',\n        '-windowstyle',\n        'hidden',\n        '-file',\n        scriptPath,\n        imagePath,\n      ]);\n      powershell.on('error', (e: { code: string }) => {\n        if (e.code === 'ENOENT') {\n          reject(\n            `The powershell command is not in you PATH environment variables. Please add it and retry.`,\n          );\n        } else {\n          reject(e);\n        }\n      });\n      powershell.on('exit', (code, signal) => {\n        // console.log('exit', code, signal);\n      });\n      powershell.stdout.on('data', (data: Buffer) => {\n        // cb(imagePath, data.toString().trim());\n        resolve(imagePath);\n      });\n    } else if (platform === 'darwin') {\n      // Mac\n      const scriptPath = path.join(\n        projectPath,\n        '/scripts/ClipboardImage/mac.applescript',\n      );\n\n      const ascript = spawn('osascript', [scriptPath, imagePath]);\n      ascript.on('error', (e) => {\n        reject(e);\n      });\n      ascript.on('exit', (code, signal) => {\n        // console.log('exit',code,signal);\n      });\n      ascript.stdout.on('data', (data: Buffer) => {\n        // cb(imagePath, data.toString().trim());\n        resolve(imagePath);\n      });\n    } else {\n      // Linux\n      const scriptPath = path.join(\n        projectPath,\n        '/scripts/ClipboardImage/linux.sh',\n      );\n\n      const ascript = spawn('sh', [scriptPath, imagePath]);\n      ascript.on('error', (e) => {\n        reject(e);\n      });\n      ascript.on('exit', (code, signal) => {\n        // console.log('exit',code,signal);\n      });\n      ascript.stdout.on('data', (data: Buffer) => {\n        const result = data.toString().trim();\n        if (result === 'no xclip') {\n          reject('You need to install xclip command first.');\n        }\n        resolve(imagePath);\n        // cb(imagePath, result);\n      });\n    }\n  });\n};\n\nexport const getClipboardImage = async (projectPath: string) => {\n  const imagePath = path.join(homedir(), '.lowcode', 'clipboardImage.png');\n  if (fs.existsSync(imagePath)) {\n    fs.removeSync(imagePath);\n  }\n  await saveClipboardImageToPath(projectPath, imagePath);\n  if (fs.existsSync(imagePath)) {\n    const base64 = fs.readFileSync(imagePath, 'base64');\n    return `data:image/png;base64,${base64}`;\n  }\n  return '';\n};\n"
  },
  {
    "path": "share/utils/config.ts",
    "content": "import * as path from 'path';\nimport * as fs from 'fs-extra';\nimport { workspace } from 'vscode';\nimport { getFileContent } from './file';\n\nexport type Config = {\n  yapi?: {\n    domain?: string;\n    projects?: {\n      name: string;\n      token: string;\n      domain: string;\n    }[];\n  };\n  mock?: {\n    mockNumber?: string;\n    mockBoolean?: string;\n    mockString?: string;\n    mockKeyWordEqual?: {\n      key: string;\n      value: string;\n    }[];\n    mockKeyWordLike?: {\n      key: string;\n      value: string;\n    }[];\n  };\n  commonlyUsedBlock?: string[];\n};\n\nexport const getConfig: () => Config = () => {\n  let config: Config;\n  if (fs.existsSync(path.join(workspace.rootPath || '', '.lowcoderc'))) {\n    config = JSON.parse(getFileContent('.lowcoderc') || '{}');\n    config.yapi?.projects?.forEach((s) => {\n      s.domain = s.domain || config.yapi?.domain || '';\n    });\n  } else {\n    config = {};\n  }\n  return config;\n};\n"
  },
  {
    "path": "share/utils/dynamicForm.ts",
    "content": "import path from 'path';\nimport fs from 'fs';\n\n/** utoolsScriptFile 和 vscodeMaterialPath 必须传入一个 */\nexport const getDynamicFormConfig = (data: {\n  utoolsScriptFile?: string;\n  vscodeMaterialPath?: string;\n  model?: object;\n}) => {\n  let configPath = '';\n  if (data.utoolsScriptFile) {\n    configPath = data.utoolsScriptFile\n      .replace('/script/src/mainBundle', '/config')\n      .replace('/script/src/main', '/config');\n  }\n  if (data.vscodeMaterialPath) {\n    configPath = path.join(data.vscodeMaterialPath, 'config');\n  }\n\n  const formConfig: {\n    schema: object;\n    scripts: { method: string; remark: string }[];\n  } = { schema: {}, scripts: [] };\n  try {\n    const fullPath = path.join(configPath);\n    let model = {};\n    let schema = {} as any;\n    let config = { scripts: [] };\n    try {\n      model = JSON.parse(\n        fs.readFileSync(path.join(fullPath, 'model.json')).toString(),\n      );\n    } catch {}\n    try {\n      schema = JSON.parse(\n        fs.readFileSync(path.join(fullPath, 'schema.json')).toString(),\n      );\n    } catch {}\n    try {\n      let configFilePath = path.join(fullPath, 'config.json');\n      if (!fs.existsSync(configFilePath)) {\n        configFilePath = path.join(fullPath, 'preview.json');\n      }\n      config = JSON.parse(fs.readFileSync(configFilePath).toString());\n    } catch {}\n    if (schema.formSchema && schema.formSchema.schema) {\n      schema = schema.formSchema.schema;\n    }\n    if (Object.keys(schema).length > 0) {\n      // 设置 page 默认 name\n      schema.name = 'page';\n      if (schema.body && Array.isArray(schema.body)) {\n        schema.body.forEach((s: Record<string, unknown>) => {\n          if (s.type === 'form') {\n            s.name = 'form';\n            s.data = data.model || model;\n          }\n        });\n      }\n    }\n    formConfig.schema = schema;\n    formConfig.scripts = config.scripts;\n  } catch {}\n  return formConfig;\n};\n"
  },
  {
    "path": "share/utils/editor.ts",
    "content": "import { Range, SnippetString, window } from 'vscode';\n\nexport const getSelectedText = () => {\n  const { selection, document } = window.activeTextEditor!;\n  return document.getText(selection).trim();\n};\n\nexport const pasteToEditor = (content: string, isInsertSnippet = true) => {\n  // vscode 本身代码片段语法\n  if (isInsertSnippet) {\n    return insertSnippet(content);\n  }\n  const { activeTextEditor } = window;\n  if (activeTextEditor === undefined) {\n    throw new Error('无打开文件');\n  }\n  return activeTextEditor?.edit((editBuilder) => {\n    // editBuilder.replace(activeTextEditor.selection, content);\n    if (activeTextEditor.selection.isEmpty) {\n      editBuilder.insert(activeTextEditor.selection.start, content);\n    } else {\n      editBuilder.replace(\n        new Range(\n          activeTextEditor.selection.start,\n          activeTextEditor.selection.end,\n        ),\n        content,\n      );\n    }\n  });\n};\n\nexport const insertSnippet = (content: string) => {\n  const { activeTextEditor } = window;\n  if (activeTextEditor === undefined) {\n    throw new Error('无打开文件');\n  }\n  return activeTextEditor.insertSnippet(new SnippetString(content));\n};\n\nexport const getFuncNameAndTypeName = () => {\n  // 这部分代码可以写在模版里，暂时保留\n  const selectedText = getSelectedText() || '';\n  let funcName = 'fetch';\n  let typeName = 'IFetchResult';\n  if (selectedText) {\n    const splitValue = selectedText.split(' ');\n    funcName = splitValue[0] || funcName;\n    if (splitValue.length > 1 && splitValue[1]) {\n      // eslint-disable-next-line prefer-destructuring\n      typeName = splitValue[1];\n    } else {\n      typeName = `I${\n        funcName.charAt(0).toUpperCase() + funcName.slice(1)\n      }Result`;\n    }\n  }\n  return {\n    funcName,\n    typeName,\n    rawSelectedText: selectedText,\n  };\n};\n"
  },
  {
    "path": "share/utils/ejs.ts",
    "content": "import * as path from 'path';\nimport * as ejs from 'ejs';\nimport glob from 'glob';\nimport * as fse from 'fs-extra';\n\nexport type YapiInfo = {\n  query_path: { path: string };\n  method: string;\n  title: string;\n  project_id: number;\n  req_params: {\n    name: string;\n    desc: string;\n  }[];\n  _id: number;\n  req_query: { required: '0' | '1'; name: string }[];\n  res_body_type: 'raw' | 'json';\n  res_body: string;\n  username: string;\n};\n\nexport type Model = {\n  type: string;\n  requestBodyType?: string;\n  funcName: string;\n  typeName: string;\n  inputValues: string[];\n  api?: YapiInfo;\n  yapiDomain?: string;\n  mockCode: string;\n  mockData: string;\n  jsonData: any;\n  jsonKeys?: string[];\n  rawSelectedText: string; // 编辑器中选中的原始文本\n  rawClipboardText: string; // 系统剪切板中的原始文本\n  activeTextEditorFilePath?: string; // 当前打开文件地址\n  createBlockPath?: string; // 创建区块的目录\n};\n\nexport const compile = (templateString: string, model: Model) =>\n  ejs.render(templateString, model);\n\nexport async function renderEjsTemplates(\n  templateData: object,\n  templateDir: string,\n) {\n  return new Promise<void>((resolve, reject) => {\n    glob(\n      '**',\n      {\n        cwd: templateDir,\n        ignore: ['node_modules/**'],\n        nodir: true,\n        dot: true,\n      },\n      (err, files) => {\n        if (err) {\n          return reject(err);\n        }\n        const templateFiles = files.filter((s) => {\n          let valid = true;\n          if (s.indexOf('.ejs') < 0) {\n            valid = false;\n          }\n          return valid;\n        });\n        Promise.all(\n          templateFiles.map((file) => {\n            const filepath = path.join(templateDir, file);\n            return renderFile(\n              filepath,\n              templateData,\n              file.includes('.keep.ejs'),\n            );\n          }),\n        )\n          .then(() => resolve())\n          .catch(reject);\n      },\n    );\n  });\n}\n\nasync function renderFile(\n  templateFilepath: string,\n  data: ejs.Data,\n  keepRawContent: boolean,\n) {\n  if (!keepRawContent) {\n    const content = await ejs.renderFile(templateFilepath, data);\n    const targetFilePath = templateFilepath\n      .replace(/\\.ejs$/, '')\n      .replace(\n        /\\$\\{.+?\\}/gi,\n        (match) => data[match.replace(/\\$|\\{|\\}/g, '')] || '',\n      );\n    await fse.rename(templateFilepath, targetFilePath);\n    await fse.writeFile(targetFilePath, content);\n  } else {\n    const targetFilePath = templateFilepath\n      .replace(/\\.keep\\.ejs$/, '.ejs')\n      .replace(\n        /\\$\\{.+?\\}/gi,\n        (match) => data[match.replace(/\\$|\\{|\\}/g, '')] || '',\n      );\n    await fse.rename(templateFilepath, targetFilePath);\n  }\n}\n"
  },
  {
    "path": "share/utils/emitter.ts",
    "content": "import mitt from 'mitt';\n\ntype Events = {\n  chatGPTChunck: { text?: string };\n  chatGPTComplete: string;\n};\n\nexport const emitter = mitt<Events>();\n"
  },
  {
    "path": "share/utils/file.ts",
    "content": "import * as path from 'path';\nimport * as fs from 'fs';\nimport { workspace } from 'vscode';\n\nexport const getFileContent = (filePath: string, fullPath = false) => {\n  let fileContent = '';\n  const fileFullPath = fullPath\n    ? filePath\n    : path.join(path.join(workspace.rootPath || ''), filePath);\n  try {\n    const fileBuffer = fs.readFileSync(fileFullPath);\n    fileContent = fileBuffer.toString();\n  } catch (error) {}\n  return fileContent;\n};\n"
  },
  {
    "path": "share/utils/json.ts",
    "content": "import * as os from 'os';\nimport * as path from 'path';\nimport * as fs from 'fs-extra';\nimport * as TJS from 'typescript-json-schema';\nimport { getConfig } from './config';\n\nexport const mockFromSchema = (schema: any) => {\n  let listIndex = 1;\n  const config = getConfig();\n  const mockConfig = config.mock;\n\n  const getMockValue = (key: string, defaultValue: string, type = 'number') => {\n    const value = defaultValue;\n    const mockKeyWordEqualConfig = mockConfig?.mockKeyWordEqual || [];\n    for (let i = 0; i < mockKeyWordEqualConfig.length; i++) {\n      if (key.toUpperCase() === mockKeyWordEqualConfig[i].key.toUpperCase()) {\n        if (typeof mockKeyWordEqualConfig[i].value === 'string') {\n          const array = mockKeyWordEqualConfig[i].value.split('&&');\n          if (array.length > 1) {\n            if (type === array[1]) {\n              return array[0];\n            }\n            return value;\n          }\n        }\n        return mockKeyWordEqualConfig[i].value;\n      }\n    }\n    const mockKeyWordLikeConfig = mockConfig?.mockKeyWordLike || [];\n    for (let i = 0; i < mockKeyWordLikeConfig.length; i++) {\n      if (\n        key.toUpperCase().indexOf(mockKeyWordLikeConfig[i].key.toUpperCase()) >\n        -1\n      ) {\n        if (typeof mockKeyWordLikeConfig[i].value === 'string') {\n          const array = mockKeyWordLikeConfig[i].value.split('&&');\n          if (array.length > 1) {\n            if (type === array[1]) {\n              return array[0];\n            }\n            return value;\n          }\n        }\n        return mockKeyWordLikeConfig[i].value;\n      }\n    }\n\n    return value;\n  };\n\n  const formatProperty = (property: any, key: string = '') => {\n    let jsonStr = '';\n    let listStr: string[] = [];\n    if (property.type === 'object') {\n      jsonStr += `${key ? `${key}: {` : ''}`;\n      Object.keys(property.properties).map((childPropertyKey) => {\n        const childProperty = property.properties[childPropertyKey];\n        const { jsonStr: childJsonStr, listStr: childListStr } = formatProperty(\n          childProperty,\n          childPropertyKey,\n        );\n        jsonStr += childJsonStr;\n        listStr = listStr.concat(childListStr);\n      });\n      jsonStr += `${key ? '},' : ''}`;\n    } else if (property.type === 'array') {\n      if (Object.keys(property.items).length > 0) {\n        const index = listIndex;\n        listIndex++;\n        let itemStr = `\n\t\t\t const list${index}=[];\n\t\t\t for(let i = 0; i < 10 ; i++){\n\t\t\t  list${index}.push(\n\t\t  `;\n        if (property.items.type === 'object') {\n          itemStr += '{';\n          Object.keys(property.items.properties).map((itemPropertyKey) => {\n            const itemProperty = property.items.properties[itemPropertyKey];\n            const { jsonStr: itemJsonStr, listStr: itemListStr } =\n              formatProperty(itemProperty, itemPropertyKey);\n            itemStr += itemJsonStr;\n            listStr = listStr.concat(itemListStr);\n          });\n          itemStr += `})}`;\n        } else {\n          if (property.items.type === 'string') {\n            itemStr += getMockValue(\n              key,\n              mockConfig?.mockString || '',\n              'string',\n            );\n          } else {\n            itemStr += getMockValue(\n              key,\n              mockConfig?.mockNumber || 'Random.natural(1000,1000)',\n            );\n          }\n          itemStr += `)}`;\n        }\n        listStr.push(itemStr);\n        jsonStr += `${key}: list${index},`;\n      } else {\n        jsonStr += `${key}: [],`;\n      }\n    } else if (property.type === 'number') {\n      jsonStr += `${key}: ${getMockValue(\n        key,\n        mockConfig?.mockNumber || 'Random.natural(1000,1000)',\n      )},`;\n    } else if (property.type === 'boolean') {\n      jsonStr += `${key}: ${getMockValue(\n        key,\n        mockConfig?.mockBoolean || 'false',\n        'boolean',\n      )},`;\n    } else if (property.type === 'string') {\n      jsonStr += `${key}: ${getMockValue(\n        key,\n        mockConfig?.mockString || 'Random.cword(5, 7)',\n        'string',\n      )},`;\n    }\n    return {\n      jsonStr,\n      listStr,\n    };\n  };\n  const { jsonStr, listStr } = formatProperty(schema);\n  return {\n    mockCode: listStr.join('\\n'),\n    mockData: `{${jsonStr}}`,\n  };\n};\n\nexport const typescriptToMock = (oriType: string) => {\n  let type = oriType;\n  const tempDir = path.join(os.homedir(), '.lowcode/temp');\n  const filePath = path.join(tempDir, 'ts.ts');\n  if (!fs.existsSync(filePath)) {\n    fs.createFileSync(filePath);\n  }\n\n  // 处理最外层是数组类型的场景\n  if (!type.trim().endsWith('}')) {\n    type = `{ result: ${type} }`;\n  }\n  fs.writeFileSync(filePath, `export interface TempType ${type}`, {\n    encoding: 'utf-8',\n  });\n\n  const program = TJS.getProgramFromFiles([filePath]);\n  const schema = TJS.generateSchema(program, 'TempType') as any;\n  if (schema === null) {\n    throw new Error('根据TS类型生成JSON Schema失败');\n  }\n  const { mockCode, mockData } = mockFromSchema(schema);\n  return {\n    mockCode,\n    mockData: !oriType.trim().endsWith('}') ? 'list1' : mockData,\n  };\n};\n"
  },
  {
    "path": "share/utils/lint.ts",
    "content": "import * as path from 'path';\nimport glob from 'glob';\nimport * as execa from 'execa';\n\nexport async function lint(option: {\n  createBlockPath: string;\n  rootPath: string;\n}) {\n  const { createBlockPath, rootPath } = option;\n  return new Promise<void>((resolve, reject) => {\n    glob(\n      '**',\n      {\n        cwd: createBlockPath,\n        ignore: ['node_modules/**'],\n        nodir: true,\n        dot: true,\n      },\n      (err, files) => {\n        if (err) {\n          return reject(err);\n        }\n        Promise.all(\n          files.map((file) => {\n            try {\n              execa.sync('node', [\n                path.join(rootPath, '/node_modules/eslint/bin/eslint.js'),\n                path.join(createBlockPath, file),\n                '--resolve-plugins-relative-to',\n                rootPath,\n                '--fix',\n              ]);\n            } catch (e) {\n              console.log(e);\n            }\n          }),\n        )\n          .then(() => resolve())\n          .catch(reject);\n      },\n    );\n  });\n}\n"
  },
  {
    "path": "share/utils/material.ts",
    "content": "import * as path from 'path';\nimport { getFileContent } from './file';\n\nexport const getMaterial = (materialPath: string) => {\n  let material: {\n    model: object;\n    schema: object;\n    preview: {\n      title?: string;\n      description?: string;\n      img?: string | string[];\n      category?: string[];\n      notShowInCommand?: boolean;\n      notShowInSnippetsList?: boolean;\n      notShowInintellisense?: boolean;\n      schema?: string;\n      scripts?: [{ method: string; remark: string }];\n    };\n    template: string;\n    commandPrompt: string;\n    viewPrompt: string;\n  } = {} as any;\n  try {\n    const fullPath = path.join(materialPath);\n    let model = {} as any;\n    let schema = {} as any;\n    let preview = {\n      img: '',\n      category: [],\n      schema: 'form-render',\n      chatGPT: { commandPrompt: '', viewPrompt: '' },\n    };\n    let template = '';\n    let commandPrompt = '';\n    let viewPrompt = '';\n    try {\n      model = JSON.parse(\n        getFileContent(path.join(fullPath, 'config', 'model.json'), true),\n      );\n    } catch {}\n    try {\n      schema = JSON.parse(\n        getFileContent(path.join(fullPath, 'config', 'schema.json'), true),\n      );\n    } catch {}\n    try {\n      preview = JSON.parse(\n        getFileContent(path.join(fullPath, 'config', 'preview.json'), true),\n      );\n    } catch {}\n    try {\n      commandPrompt = getFileContent(\n        path.join(fullPath, 'config', 'commandPrompt.ejs'),\n        true,\n      );\n    } catch {}\n    try {\n      viewPrompt = getFileContent(\n        path.join(fullPath, 'config', 'viewPrompt.ejs'),\n        true,\n      );\n    } catch {}\n    if (!preview.img) {\n      preview.img =\n        'https://gitee.com/img-host/img-host/raw/master/2020/11/05/1604587962875.jpg';\n    }\n    if (!preview.schema) {\n      preview.schema = 'form-render';\n    }\n\n    try {\n      template = getFileContent(\n        path.join(fullPath, 'src', 'template.ejs'),\n        true,\n      );\n    } catch {}\n    if (schema.formSchema) {\n      if (schema.formSchema.formData) {\n        model = schema.formSchema.formData;\n      }\n      schema = schema.formSchema.schema;\n    }\n    if (Object.keys(schema).length > 0 && preview.schema === 'amis') {\n      // 设置 page 默认 name\n      schema.name = 'page';\n      if (schema.body && Array.isArray(schema.body)) {\n        schema.body.forEach((s: Record<string, unknown>) => {\n          if (s.type === 'form') {\n            s.name = 'form';\n            if (s.data && Object.keys(model).length === 0) {\n              model = s.data;\n            } else if (!s.data && Object.keys(model).length > 0) {\n              s.data = model;\n            }\n          }\n        });\n      }\n    }\n    material = {\n      model,\n      schema,\n      preview,\n      template,\n      commandPrompt,\n      viewPrompt,\n    };\n  } catch {}\n  return material;\n};\n"
  },
  {
    "path": "share/utils/platformIndependent/json.ts",
    "content": "import * as os from 'os';\nimport * as path from 'path';\nimport * as fs from 'fs-extra';\nimport * as TJS from 'typescript-json-schema';\nimport { getShareData } from '../shareData';\n\nexport type Config = {\n  mock?: {\n    mockNumber?: string;\n    mockBoolean?: string;\n    mockString?: string;\n    mockKeyWordEqual?: {\n      key: string;\n      value: string;\n    }[];\n    mockKeyWordLike?: {\n      key: string;\n      value: string;\n    }[];\n  };\n  commonlyUsedBlock?: string[];\n};\n\nexport const getMockConfig: () => Config = () => {\n  const { activeWindow } = getShareData();\n  let config: Config;\n  if (fs.existsSync(path.join(activeWindow || '', '.lowcoderc'))) {\n    config = fs.readJSONSync(path.join(activeWindow || '', '.lowcoderc'));\n  } else {\n    config = {};\n  }\n  return config;\n};\n\nexport const mockFromSchema = (schema: any) => {\n  let listIndex = 1;\n  const config = getMockConfig();\n  const mockConfig = config.mock;\n\n  const getMockValue = (key: string, defaultValue: string, type = 'number') => {\n    const value = defaultValue;\n    const mockKeyWordEqualConfig = mockConfig?.mockKeyWordEqual || [];\n    for (let i = 0; i < mockKeyWordEqualConfig.length; i++) {\n      if (key.toUpperCase() === mockKeyWordEqualConfig[i].key.toUpperCase()) {\n        if (typeof mockKeyWordEqualConfig[i].value === 'string') {\n          const array = mockKeyWordEqualConfig[i].value.split('&&');\n          if (array.length > 1) {\n            if (type === array[1]) {\n              return array[0];\n            }\n            return value;\n          }\n        }\n        return mockKeyWordEqualConfig[i].value;\n      }\n    }\n    const mockKeyWordLikeConfig = mockConfig?.mockKeyWordLike || [];\n    for (let i = 0; i < mockKeyWordLikeConfig.length; i++) {\n      if (\n        key.toUpperCase().indexOf(mockKeyWordLikeConfig[i].key.toUpperCase()) >\n        -1\n      ) {\n        if (typeof mockKeyWordLikeConfig[i].value === 'string') {\n          const array = mockKeyWordLikeConfig[i].value.split('&&');\n          if (array.length > 1) {\n            if (type === array[1]) {\n              return array[0];\n            }\n            return value;\n          }\n        }\n        return mockKeyWordLikeConfig[i].value;\n      }\n    }\n\n    return value;\n  };\n\n  const formatProperty = (property: any, key: string = '') => {\n    let jsonStr = '';\n    let listStr: string[] = [];\n    if (property.type === 'object') {\n      jsonStr += `${key ? `${key}: {` : ''}`;\n      Object.keys(property.properties).map((childPropertyKey) => {\n        const childProperty = property.properties[childPropertyKey];\n        const { jsonStr: childJsonStr, listStr: childListStr } = formatProperty(\n          childProperty,\n          childPropertyKey,\n        );\n        jsonStr += childJsonStr;\n        listStr = listStr.concat(childListStr);\n      });\n      jsonStr += `${key ? '},' : ''}`;\n    } else if (property.type === 'array') {\n      if (Object.keys(property.items).length > 0) {\n        const index = listIndex;\n        listIndex++;\n        let itemStr = `\n\t\t\t const list${index}=[];\n\t\t\t for(let i = 0; i < 10 ; i++){\n\t\t\t  list${index}.push(\n\t\t  `;\n        if (property.items.type === 'object') {\n          itemStr += '{';\n          Object.keys(property.items.properties).map((itemPropertyKey) => {\n            const itemProperty = property.items.properties[itemPropertyKey];\n            const { jsonStr: itemJsonStr, listStr: itemListStr } =\n              formatProperty(itemProperty, itemPropertyKey);\n            itemStr += itemJsonStr;\n            listStr = listStr.concat(itemListStr);\n          });\n          itemStr += `})}`;\n        } else {\n          if (property.items.type === 'string') {\n            itemStr += getMockValue(\n              key,\n              mockConfig?.mockString || '',\n              'string',\n            );\n          } else {\n            itemStr += getMockValue(\n              key,\n              mockConfig?.mockNumber || 'Random.natural(1000,1000)',\n            );\n          }\n          itemStr += `)}`;\n        }\n        listStr.push(itemStr);\n        jsonStr += `${key}: list${index},`;\n      } else {\n        jsonStr += `${key}: [],`;\n      }\n    } else if (property.type === 'number') {\n      jsonStr += `${key}: ${getMockValue(\n        key,\n        mockConfig?.mockNumber || 'Random.natural(1000,1000)',\n      )},`;\n    } else if (property.type === 'boolean') {\n      jsonStr += `${key}: ${getMockValue(\n        key,\n        mockConfig?.mockBoolean || 'false',\n        'boolean',\n      )},`;\n    } else if (property.type === 'string') {\n      jsonStr += `${key}: ${getMockValue(\n        key,\n        mockConfig?.mockString || 'Random.cword(5, 7)',\n        'string',\n      )},`;\n    }\n    return {\n      jsonStr,\n      listStr,\n    };\n  };\n  const { jsonStr, listStr } = formatProperty(schema);\n  return {\n    mockCode: listStr.join('\\n'),\n    mockData: `{${jsonStr}}`,\n  };\n};\n\nexport const typescriptToMock = (oriType: string) => {\n  let type = oriType;\n  const tempDir = path.join(os.homedir(), '.lowcode/temp');\n  const filePath = path.join(tempDir, 'ts.ts');\n  if (!fs.existsSync(filePath)) {\n    fs.createFileSync(filePath);\n  }\n\n  // 处理最外层是数组类型的场景\n  if (!type.trim().endsWith('}')) {\n    type = `{ result: ${type} }`;\n  }\n  fs.writeFileSync(filePath, `export interface TempType ${type}`, {\n    encoding: 'utf-8',\n  });\n\n  const program = TJS.getProgramFromFiles([filePath]);\n  const schema = TJS.generateSchema(program, 'TempType') as any;\n  if (schema === null) {\n    throw new Error('根据TS类型生成JSON Schema失败');\n  }\n  const { mockCode, mockData } = mockFromSchema(schema);\n  return {\n    mockCode,\n    mockData: !oriType.trim().endsWith('}') ? 'list1' : mockData,\n  };\n};\n"
  },
  {
    "path": "share/utils/shareData.ts",
    "content": "import path from 'path';\nimport { homedir } from 'os';\nimport * as fs from 'fs-extra';\n\nconst dataFile = path.join(homedir(), '.lowcode', 'data.json');\n\nexport type ShareData = {\n  activeWindow?: string;\n  selectedFolder?: string;\n  oneAPI?: {\n    apiKey: string;\n    hostname?: string;\n    apiPath?: string;\n    port?: number;\n    notHttps?: boolean;\n    model?: string;\n    maxTokens?: number;\n    proxyUrl?: string;\n    /**\n     * @description 使用当前配置\n     * @type {boolean}\n     */\n    use: boolean;\n  }[];\n};\n\nexport const getShareData = () => {\n  if (fs.existsSync(dataFile)) {\n    const data = fs.readJSONSync(dataFile) as ShareData;\n    if (data.activeWindow) {\n      data.activeWindow =\n        process.platform === 'win32' && data.activeWindow.startsWith('/')\n          ? data.activeWindow.substring(1)\n          : data.activeWindow;\n    }\n    return data;\n  }\n  return {} as ShareData;\n};\n\nexport const saveShareData = (data: ShareData) => {\n  fs.writeJSONSync(dataFile, { ...getShareData(), ...data }, { spaces: 2 });\n};\n\nexport const oneAPIConfig = () => {\n  const { oneAPI } = getShareData();\n  if (oneAPI && oneAPI.length > 0) {\n    return oneAPI.find((s) => s.use) || oneAPI[0];\n  }\n  return undefined;\n};\n"
  },
  {
    "path": "share/utils/tsx.ts",
    "content": "import * as path from 'path';\nimport { decode } from 'html-entities';\nimport * as ReactDOMServer from 'react-dom/server';\nimport glob from 'glob';\nimport * as fse from 'fs-extra';\nimport ts from 'typescript';\n\nexport async function renderTemplates(props: object, templateDir: string) {\n  return new Promise<void>((resolve, reject) => {\n    glob(\n      '**',\n      {\n        cwd: templateDir,\n        ignore: ['node_modules/**'],\n        nodir: true,\n        dot: true,\n      },\n      (err, files) => {\n        if (err) {\n          return reject(err);\n        }\n        const templateFiles = files.filter((s) => {\n          let valid = true;\n          if (s.indexOf('.template.tsx') < 0) {\n            valid = false;\n          }\n          return valid;\n        });\n        Promise.all(\n          templateFiles.map((file) => {\n            const filepath = path.join(templateDir, file);\n            return renderFile(filepath, props);\n          }),\n        )\n          .then(() => resolve())\n          .catch(reject);\n      },\n    );\n  });\n}\n\nasync function renderFile(templateFilepath: string, props: object) {\n  const tsxContentStr = fse.readFileSync(templateFilepath).toString();\n  const transpileResult = ts.transpileModule(tsxContentStr, {\n    compilerOptions: {\n      jsx: ts.JsxEmit.React,\n      module: ts.ModuleKind.ES2015,\n      strict: false,\n      moduleResolution: ts.ModuleResolutionKind.NodeNext,\n      target: ts.ScriptTarget.ES2015,\n    },\n  });\n  fse.writeFileSync(path.join(templateFilepath), transpileResult.outputText);\n  const templateJsFilepath = templateFilepath.replace(\n    /\\.template.tsx$/,\n    '.template.js',\n  );\n  await fse.rename(templateFilepath, templateJsFilepath);\n  delete require.cache[require.resolve(templateJsFilepath)];\n\n  const script = require(templateJsFilepath);\n  const markup = ReactDOMServer.renderToStaticMarkup(script.default(props));\n  const targetFilePath = templateJsFilepath\n    .replace(/\\.template.js$/, '')\n    .replace(\n      /\\$\\{.+?\\}/gi,\n      (match) => props[match.replace(/\\$|\\{|\\}/g, '')] || '',\n    );\n  await fse.rename(templateJsFilepath, targetFilePath);\n  await fse.writeFile(targetFilePath, decode(markup));\n}\n"
  },
  {
    "path": "share/utils/uTools.ts",
    "content": "import path from 'path';\nimport * as fs from 'fs-extra';\nimport { createChatCompletion } from '../LLM/openaiV2';\n\nexport const screenCapture = () =>\n  new Promise<string>((resolve, reject) => {\n    utools.screenCapture((res) => {\n      resolve(res);\n    });\n  });\n\ntype LLMMessage = (\n  | {\n      role: 'system';\n      content: string;\n    }\n  | {\n      role: 'user';\n      content:\n        | string\n        | (\n            | {\n                type: 'image_url';\n                image_url: { url: string };\n              }\n            | { type: 'text'; text: string }\n          )[];\n    }\n)[];\nexport const askChatGPT = async (data: {\n  messages: LLMMessage;\n  handleChunk: (chunck: string) => void;\n  hostname?: string;\n  apiKey?: string;\n  apiPath?: string;\n  port?: number;\n  notHttps?: boolean;\n  model?: string;\n  maxTokens?: number;\n}) => {\n  const res = await createChatCompletion({\n    apiKey: data.apiKey,\n    hostname: data.hostname,\n    apiPath: data.apiPath,\n    port: data.port,\n    notHttps: data.notHttps,\n    messages: data.messages,\n    model: data.model,\n    maxTokens: data.maxTokens,\n    handleChunk(chunck) {\n      data.handleChunk(chunck.text || '');\n    },\n  });\n  return { content: res };\n};\n\nexport const getBlockJsonValidSchema = (\n  mainScriptFile: string,\n  schemaFileName = 'schema.ts',\n) => {\n  const configPath = getBlockConfigPath(mainScriptFile);\n  return fs.readFileSync(path.join(configPath, schemaFileName), 'utf8');\n};\n\n/** 获取脚本目录 */\nexport const getBlockPath = (mainScriptFile: string) => {\n  return path.join(\n    mainScriptFile\n      .replace('/script/src/mainBundle', '')\n      .replace('/script/src/main', ''),\n  );\n};\n\nexport const getBlockConfigPath = (mainScriptFile: string) => {\n  const configPath = path.join(\n    mainScriptFile\n      .replace('/script/src/mainBundle', '/config')\n      .replace('/script/src/main', '/config'),\n  );\n  return configPath;\n};\n\nexport const getBlockTemplatePath = (mainScriptFile: string) => {\n  const configPath = path.join(\n    mainScriptFile\n      .replace('/script/src/mainBundle', '/src')\n      .replace('/script/src/main', '/src'),\n  );\n  return configPath;\n};\n\nexport const ocr: (data: {\n  base64: string;\n  model: 'structure_table' | 'ocr_system';\n}) => Promise<{\n  log_id: string;\n  error_code: number;\n  error_message: string;\n  result?: {\n    texts?: string[];\n  };\n}> = async (data) => {\n  const base64Array = data.base64.match(\n    /^data:(image\\/(?:png|jpg|jpeg));base64,(.+)$/,\n  )!;\n  const type = base64Array[1];\n  const atob = window.atob(base64Array[2]);\n  const uint8Array = new Uint8Array(atob.length);\n  for (let i = 0; i < atob.length; i++) {\n    uint8Array[i] = atob.charCodeAt(i);\n  }\n  const blob = new Blob([uint8Array], { type });\n  const form = new window.FormData();\n  form.append('image', blob);\n  const i = {\n    method: 'POST',\n    headers: { Accept: 'application/json' },\n    body: form,\n  };\n  try {\n    const tokenRes = await window.utools.fetchUserServerTemporaryToken();\n    const res = await fetch(\n      `https://ocr.u-tools.cn:7999/ocr/?model=${data.model}&access_token=${tokenRes.token}`,\n      i,\n    );\n    try {\n      const json = await res.json();\n      return json;\n    } catch (ex) {\n      return Promise.reject(ex);\n    }\n  } catch (ex) {\n    return Promise.reject(ex);\n  }\n};\n\nexport const icon =\n  'data:image/png;base64,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';\n"
  },
  {
    "path": "tsconfig.compiler.json",
    "content": "{\n\t\"compilerOptions\": {\n\t\t\"target\": \"ESNext\",\n\t\t\"useDefineForClassFields\": true,\n\t\t\"module\": \"commonjs\",\n\t\t\"moduleResolution\": \"Node\",\n\t\t\"experimentalDecorators\": true,\n\t\t\"emitDecoratorMetadata\": true,\n\t\t\"strict\": true,\n\t\t\"jsx\": \"react-jsx\",\n\t\t\"sourceMap\": false,\n\t\t\"resolveJsonModule\": true,\n\t\t\"isolatedModules\": true,\n\t\t\"esModuleInterop\": true,\n\t\t\"noUnusedLocals\": false,\n\t\t\"noUnusedParameters\": false,\n\t\t\"strictNullChecks\": true,\n\t\t\"noImplicitAny\": false,\n\t\t\"allowJs\": true,\n\t\t\"lib\": [\n\t\t\t\"ESNext\",\n\t\t\t\"DOM\"\n\t\t],\n\t\t\"skipLibCheck\": true,\n\t\t\"allowSyntheticDefaultImports\": true,\n\t\t\"baseUrl\": \".\",\n\t\t\"rootDir\": \".\",\n\t\t\"paths\": {\n\t\t\t\"@share/*\": [\n\t\t\t\t\"share/*\"\n\t\t\t]\n\t\t},\n\t\t\"outDir\": \"./dist\",\n\t\t\"types\": [\n\t\t\t\"utools-api-types\",\n\t\t\t\"node\"\n\t\t]\n\t},\n\t\"exclude\": [\n\t\t\"node_modules\",\n\t\t\"dist\",\n\t\t\"llm\",\n\t\t\"build.js\",\n\t\t\"uTools.js\",\n\t\t\"esbuild.js\"\n\t]\n}"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ESNext\",\n    \"useDefineForClassFields\": true,\n    \"module\": \"commonjs\",\n    \"moduleResolution\": \"Node\",\n    \"experimentalDecorators\": true,\n    \"emitDecoratorMetadata\": true,\n    \"strict\": true,\n    \"jsx\": \"react-jsx\",\n    \"sourceMap\": false,\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"esModuleInterop\": true,\n    \"noUnusedLocals\": false,\n    \"noUnusedParameters\": false,\n    \"strictNullChecks\": true,\n    \"noImplicitAny\": false,\n    \"allowJs\": true,\n    \"lib\": [\n      \"ESNext\",\n      \"DOM\"\n    ],\n    \"skipLibCheck\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"baseUrl\": \".\",\n    \"rootDir\": \".\",\n    \"paths\": {\n      \"@share/*\": [\n        \"share/*\"\n      ]\n    },\n    \"outDir\": \"./dist\",\n    \"types\": [\n      \"utools-api-types\",\n      \"node\"\n    ]\n  },\n  \"exclude\": [\n    \"node_modules\",\n    \"dist\"\n  ]\n}"
  },
  {
    "path": "uTools/Ask ChatGPT/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/Ask ChatGPT/script/src/main.ts",
    "content": "import { clipboard } from 'electron';\nimport { askChatGPT as askOpenai } from '@share/utils/uTools';\nimport { AskChatGPT } from '@share/uTools/webviewBaseController';\n\nexport const bootstrap = async (scriptFile?: string) => {\n  utools.redirect(['lowcode', 'lowcode'], {\n    type: 'text',\n    data: JSON.stringify({\n      scriptFile,\n      route: '/chat',\n      content: clipboard.readText(),\n    }),\n  });\n};\n\n// 给页面调用的\nexport const askChatGPT: AskChatGPT = (data) =>\n  askOpenai({ ...data, model: undefined });\n"
  },
  {
    "path": "uTools/Ask ChatGPT-生成 value-label 格式 JSON/config/schema.ts",
    "content": "export type IOption = { value: string; label: string }[];\n"
  },
  {
    "path": "uTools/Ask ChatGPT-生成 value-label 格式 JSON/config/template.ejs",
    "content": "export const <%- rawSelectedText %>Options = <%- content %>\n\nexport const <%- rawSelectedText %>Map = <%- rawSelectedText %>Options.reduce((obj, { label, value }) => {\n  obj[value] = label\n  return obj\n}, {})\n"
  },
  {
    "path": "uTools/Ask ChatGPT-生成 value-label 格式 JSON/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/Ask ChatGPT-生成 value-label 格式 JSON/script/src/main.ts",
    "content": "import path from 'path';\nimport fs from 'fs';\nimport { clipboard } from 'electron';\nimport { validate } from '@share/TypeChatSlim/utools';\nimport { compile as compileEjs } from '@share/utils/ejs';\nimport {\n  askChatGPT as askOpenai,\n  getBlockConfigPath,\n  getBlockJsonValidSchema,\n} from '@share/utils/uTools';\n\nexport const bootstrap = async (scriptFile?: string) => {\n  const configPath = getBlockConfigPath(scriptFile!);\n  const schema = getBlockJsonValidSchema(scriptFile!);\n  const clipboardText =\n    (clipboard.readText() || '').trim() ||\n    '客户验收状态:1.无需验收、2.待验收、3已验收';\n  const typeName = 'IOption';\n  const requestPrompt =\n    `You are a service that translates user requests into JSON objects of type \"${typeName}\" according to the following TypeScript definitions:\\n` +\n    `\\`\\`\\`\\n${schema}\\`\\`\\`\\n` +\n    `The following is a user request:\\n` +\n    `\"\"\"\\n${clipboardText}\\n\"\"\"\\n` +\n    `The following is the user request translated into a JSON object with 2 spaces of indentation and no properties with the value undefined:\\n`;\n  const content = await askOpenai({\n    messages: [{ role: 'user', content: requestPrompt }],\n    handleChunk: () => {},\n  });\n  const valid = validate(content.content, schema, typeName);\n  if (valid.success) {\n    const template = fs.readFileSync(\n      path.join(configPath, 'template.ejs'),\n      'utf8',\n    );\n    const code = compileEjs(template, {\n      rawSelectedText: '请手动修改名称',\n      content: JSON.stringify(valid.data),\n    } as any);\n    utools.outPlugin();\n    utools.hideMainWindowPasteText(code);\n  } else {\n    return valid.message;\n  }\n};\n"
  },
  {
    "path": "uTools/Ask ChatGPT-生成 value-label 格式 JSON - Form/config/schema.ts",
    "content": "export type IOption = { value: string; label: string }[];\n"
  },
  {
    "path": "uTools/Ask ChatGPT-生成 value-label 格式 JSON - Form/config/template.ejs",
    "content": "export const <%- rawSelectedText %>Options = <%- content %>\n\nexport const <%- rawSelectedText %>Map = <%- rawSelectedText %>Options.reduce((obj, { label, value }) => {\n  obj[value] = label\n  return obj\n}, {})\n"
  },
  {
    "path": "uTools/Ask ChatGPT-生成 value-label 格式 JSON - Form/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/Ask ChatGPT-生成 value-label 格式 JSON - Form/script/src/main.ts",
    "content": "import path from 'path';\nimport fs from 'fs';\nimport { clipboard } from 'electron';\nimport { validate } from '@share/TypeChatSlim/utools';\nimport { compile as compileEjs } from '@share/utils/ejs';\nimport {\n  askChatGPT as askOpenai,\n  getBlockConfigPath,\n  getBlockJsonValidSchema,\n} from '@share/utils/uTools';\n\nexport const bootstrap = async (scriptFile?: string) => {\n  const schema = getBlockJsonValidSchema(scriptFile!);\n  const clipboardText =\n    (clipboard.readText() || '').trim() ||\n    '客户验收状态:1.无需验收、2.待验收、3已验收';\n  const typeName = 'IOption';\n  const requestPrompt =\n    `You are a service that translates user requests into JSON objects of type \"${typeName}\" according to the following TypeScript definitions:\\n` +\n    `\\`\\`\\`\\n${schema}\\`\\`\\`\\n` +\n    `The following is a user request:\\n` +\n    `\"\"\"\\n${clipboardText}\\n\"\"\"\\n` +\n    `The following is the user request translated into a JSON object with 2 spaces of indentation and no properties with the value undefined:\\n`;\n  utools.redirect(['lowcode', 'lowcode'], {\n    type: 'text',\n    data: JSON.stringify({\n      scriptFile,\n      route: '/chat',\n      content: requestPrompt,\n    }),\n  });\n};\n\ntype LLMMessage = (\n  | {\n      role: 'system';\n      content: string;\n    }\n  | {\n      role: 'user';\n      content:\n        | string\n        | (\n            | {\n                type: 'image_url';\n                image_url: { url: string };\n              }\n            | { type: 'text'; text: string }\n          )[];\n    }\n)[];\n\n// 给页面调用的\nexport const askChatGPT = async (data: {\n  messages: LLMMessage;\n  handleChunk: (chunck: string) => void;\n  scriptFile: string;\n}) => {\n  const configPath = getBlockConfigPath(data.scriptFile);\n  const schema = getBlockJsonValidSchema(data.scriptFile);\n  const template = fs.readFileSync(\n    path.join(configPath, 'template.ejs'),\n    'utf8',\n  );\n  const typeName = 'IOption';\n\n  if (\n    data.messages.length >= 3 &&\n    (data.messages[data.messages.length - 1].content as string).includes('>>>')\n  ) {\n    const name = (data.messages[data.messages.length - 1].content as string)\n      .split('>>>')[1]\n      .trim();\n    const jsonValid = validate(\n      data.messages[data.messages.length - 2].content as string,\n      schema,\n      typeName,\n    );\n    if (jsonValid.success) {\n      setTimeout(() => {\n        const code = compileEjs(template, {\n          rawSelectedText: name || '请手动修改名称',\n          content: JSON.stringify(jsonValid.data),\n        } as any);\n        clipboard.writeText(code);\n        utools.outPlugin();\n        utools.hideMainWindowPasteText(code);\n      }, 300);\n    } else {\n      data.handleChunk(`\n\n> 生成代码时 JSON 校验不通过\n\n${jsonValid.message}\n\t\t\t\t\t\t`);\n    }\n    return '';\n  }\n  const content = await askOpenai({\n    messages: data.messages,\n    handleChunk: data.handleChunk,\n  });\n  const valid = validate(content.content, schema, typeName);\n  if (valid.success) {\n    data.handleChunk(`\n\nJSON 校验通过，输入\\`>>>\\`生成代码\n\t\t\t`);\n  } else {\n    data.handleChunk(`\n\n> JSON 校验不通过\n\n${valid.message}\n\t\t\t\t\t\t`);\n  }\n  return content;\n};\n"
  },
  {
    "path": "uTools/Ask ChatGPT-生成 value-label 格式 JSON - Prompt/config/schema.ts",
    "content": "export type IOption = { value: string; label: string }[];\n"
  },
  {
    "path": "uTools/Ask ChatGPT-生成 value-label 格式 JSON - Prompt/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/Ask ChatGPT-生成 value-label 格式 JSON - Prompt/script/src/main.ts",
    "content": "import { clipboard } from 'electron';\nimport { getBlockJsonValidSchema } from '@share/utils/uTools';\n\nexport const bootstrap = async (scriptFile?: string) => {\n  const schema = getBlockJsonValidSchema(scriptFile!);\n  const clipboardText =\n    (clipboard.readText() || '').trim() ||\n    '客户验收状态:1.无需验收、2.待验收、3已验收';\n  const typeName = 'IOption';\n  const requestPrompt =\n    `You are a service that translates user requests into JSON objects of type \"${typeName}\" according to the following TypeScript definitions:\\n` +\n    `\\`\\`\\`\\n${schema}\\`\\`\\`\\n` +\n    `The following is a user request:\\n` +\n    `\"\"\"\\n${clipboardText}\\n\"\"\"\\n` +\n    `The following is the user request translated into a JSON object with 2 spaces of indentation and no properties with the value undefined:\\n`;\n  clipboard.writeText(requestPrompt);\n  utools.showNotification('prompt 已经写入剪贴板');\n  return requestPrompt;\n};\n"
  },
  {
    "path": "uTools/Ask Gemini/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/Ask Gemini/script/src/main.ts",
    "content": "import { clipboard } from 'electron';\n\nexport const bootstrap = async () => {\n  utools.setUBrowserProxy({ proxyRules: 'http://127.0.0.1:7890' });\n  utools.ubrowser\n    // .devTools('bottom')\n    .useragent('Chrome')\n    .goto('https://gemini.google.com/')\n    .wait('rich-textarea')\n    .when('rich-textarea')\n    .wait(1000)\n    .focus('rich-textarea')\n    // .wait(300)\n    // .paste('你好')\n    // .wait(1000)\n    // .press('Enter')\n    .end()\n    .run({});\n  utools.outPlugin();\n  utools.hideMainWindow();\n};\n"
  },
  {
    "path": "uTools/Ask Groq/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/Ask Groq/script/src/main.ts",
    "content": "import { clipboard } from 'electron';\n\nexport const bootstrap = async () => {\n  utools.setUBrowserProxy({ proxyRules: 'http://127.0.0.1:7890' });\n  utools.ubrowser\n    // .devTools('bottom')\n    .useragent('Chrome')\n    .goto('https://groq.com/')\n    .wait('#model-selector')\n    .wait('#chat')\n    .when('#chat')\n    .wait(1000)\n    .focus('#chat')\n    // .wait(300)\n    // .paste('你好')\n    // .wait(1000)\n    // .press('Enter')\n    .end()\n    .run({});\n  utools.outPlugin();\n  utools.hideMainWindow();\n};\n"
  },
  {
    "path": "uTools/Ask Kimi/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/Ask Kimi/script/src/main.ts",
    "content": "import { clipboard } from 'electron';\n\nexport const bootstrap = async () => {\n  utools.ubrowser\n    .goto('https://kimi.moonshot.cn/')\n    .wait('div[role=\"textbox\"]')\n    .focus('div[role=\"textbox\"]')\n    // .paste('你好')\n    // .wait(300)\n    // .press('Enter')\n    .run({})\n    .catch((err) => {\n      utools.showNotification(err.message);\n    });\n  utools.outPlugin();\n  utools.hideMainWindow();\n};\n"
  },
  {
    "path": "uTools/Ask Perplexity/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/Ask Perplexity/script/src/main.ts",
    "content": "import { clipboard } from 'electron';\n\nexport const bootstrap = async () => {\n  utools.setUBrowserProxy({ proxyRules: 'http://127.0.0.1:7890' });\n  utools.ubrowser\n    // .devTools('bottom')\n    // .useragent('Chrome')\n    // .useragent(\n    //   'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0',\n    // ) // windows\n    // .useragent(\n    //   'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) uTools/4.0.1 Chrome/108.0.5359.215 Electron/22.3.12 Safari/537.36',\n    // )\n    .goto('https://www.perplexity.ai/')\n    .wait('textarea')\n    .when('textarea')\n    .wait(1000)\n    .focus('textarea')\n    // .wait(300)\n    // .paste('你好')\n    // .wait(1000)\n    // .press('Enter')\n    .end()\n    .run({});\n  utools.outPlugin();\n  utools.hideMainWindow();\n};\n"
  },
  {
    "path": "uTools/Chat With Form Demo/config/config.json",
    "content": "{\n\t\"scripts\": []\n}"
  },
  {
    "path": "uTools/Chat With Form Demo/config/model.json",
    "content": "{\n\t\"file\": \"\",\n\t\"items\": []\n}"
  },
  {
    "path": "uTools/Chat With Form Demo/config/schema.json",
    "content": "{\n\t\"type\": \"page\",\n\t\"body\": [\n\t\t{\n\t\t\t\"type\": \"form\",\n\t\t\t\"body\": [\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"input-file\",\n\t\t\t\t\t\"name\": \"file\",\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"accept\": \"*\",\n\t\t\t\t\t\"id\": \"u:c04ee740c509\",\n\t\t\t\t\t\"asBase64\": true,\n\t\t\t\t\t\"btnLabel\": \"文件上传\",\n\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\"uploadType\": \"bos\",\n\t\t\t\t\t\"proxy\": false,\n\t\t\t\t\t\"autoUpload\": true,\n\t\t\t\t\t\"useChunk\": false,\n\t\t\t\t\t\"drag\": true,\n\t\t\t\t\t\"asBlob\": false,\n\t\t\t\t\t\"bos\": \"default\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\"label\": \"选项\",\n\t\t\t\t\t\"name\": \"select\",\n\t\t\t\t\t\"id\": \"u:fce7d967cf31\",\n\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\"source\": \"${items}\"\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"title\": \"\",\n\t\t\t\"submitText\": \"\",\n\t\t\t\"id\": \"u:750900f46569\",\n\t\t\t\"actions\": [],\n\t\t\t\"feat\": \"Insert\",\n\t\t\t\"dsType\": \"api\",\n\t\t\t\"labelAlign\": \"left\"\n\t\t}\n\t],\n\t\"pullRefresh\": {\n\t\t\"disabled\": true\n\t},\n\t\"regions\": [\n\t\t\"body\"\n\t],\n\t\"style\": {},\n\t\"asideResizor\": false,\n\t\"themeCss\": {\n\t\t\"baseControlClassName\": {\n\t\t\t\"boxShadow:default\": \" 0px 0px 0px 0px transparent\"\n\t\t}\n\t},\n\t\"id\": \"u:92f76614d33d\"\n}"
  },
  {
    "path": "uTools/Chat With Form Demo/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/Chat With Form Demo/script/src/controller.ts",
    "content": "import path from 'path';\nimport * as fs from 'fs-extra';\nimport * as execa from 'execa';\nimport * as ejs from 'ejs';\nimport axios from 'axios';\nimport { clipboard } from 'electron';\nimport { generalBasic } from '@share/BaiduOCR/index';\nimport { getShareData } from '@share/utils/shareData';\nimport { renderEjsTemplates } from '@share/utils/ejs';\nimport { typescriptToMock } from '@share/utils/platformIndependent/json';\nimport { MethodHandle } from '@share/uTools/webviewBaseController';\nimport { getBlockJsonValidSchema, getBlockPath } from '@share/utils/uTools';\n\nexport const openChatGPT: MethodHandle = async (data) => {\n  const schema = getBlockJsonValidSchema(data.scriptFile);\n  const clipboardText = JSON.stringify(data.model);\n  const typeName = 'IOption';\n  const requestPrompt =\n    `You are a service that translates user requests into JSON objects of type \"${typeName}\" according to the following TypeScript definitions:\\n` +\n    `\\`\\`\\`\\n${schema}\\`\\`\\`\\n` +\n    `The following is a user request:\\n` +\n    `\"\"\"\\n${clipboardText}\\n\"\"\"\\n` +\n    `The following is the user request translated into a JSON object with 2 spaces of indentation and no properties with the value undefined:\\n`;\n  return {\n    updateModelImmediately: true,\n    onlyUpdateParams: false,\n    params: '',\n    showChat: true,\n    chatContent: requestPrompt,\n    model: data.model,\n  };\n};\n"
  },
  {
    "path": "uTools/Chat With Form Demo/script/src/main.ts",
    "content": "import {\n  AskChatGPT,\n  LLMMessage,\n  MethodHandle,\n} from '@share/uTools/webviewBaseController';\nimport { askChatGPT as askOpenai } from '@share/utils/uTools';\nimport * as controller from './controller';\n\nexport const bootstrap = async (scriptFile?: string) => {\n  utools.redirect(['lowcode', 'lowcode'], {\n    type: 'text',\n    data: JSON.stringify({\n      scriptFile,\n      route: '/chat',\n      form: {\n        name: 123,\n      },\n    }),\n  });\n};\n\n// 给页面调用的\nexport const askChatGPT: AskChatGPT = async (data: {\n  messages: LLMMessage;\n  handleChunk: (chunck: string) => void;\n  model?: object;\n}) => {\n  // data.handleChunk(JSON.stringify(data.model || { a: 123 }));\n  const res = await askOpenai({ ...data, model: undefined });\n  return {\n    content: res.content,\n    showForm: true,\n    updateModelImmediately: true,\n    model: {\n      ...data.model,\n      items: [\n        {\n          label: 'A',\n          value: 'a',\n        },\n        {\n          label: 'B',\n          value: 'b',\n        },\n        {\n          label: 'C',\n          value: 'c',\n        },\n      ],\n    },\n  };\n};\n\nexport const runDynamicFormScript: MethodHandle = (data) => {\n  if (controller[data.method]) {\n    return controller[data.method](data);\n  }\n  return Promise.reject(`方法不存在：${data.method}`);\n};\n"
  },
  {
    "path": "uTools/Git 获取当前用户最近一次 Commit 信息/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/Git 获取当前用户最近一次 Commit 信息/script/src/main.ts",
    "content": "import { clipboard } from 'electron';\nimport * as execa from 'execa';\nimport { getShareData } from '@share/utils/shareData';\n\nexport const bootstrap = (scriptFile?: string) => {\n  const { activeWindow } = getShareData();\n  try {\n    const projectPath =\n      utools.isWindows() && activeWindow?.startsWith('/')\n        ? activeWindow.substring(1)\n        : activeWindow;\n    const userName = execa.sync('git', [\n      '-C',\n      projectPath || '.',\n      'config',\n      'user.name',\n    ]);\n    const res = execa.sync('git', [\n      '-C',\n      projectPath || '.',\n      'log',\n      '-1',\n      '--pretty=format:%s',\n      `--author=${userName.stdout}`,\n      // 'log -1 --pretty=format:\"%s\" --author=\"$(git config user.name)\"',\n    ]);\n    if (res.stdout) {\n      utools.outPlugin();\n      utools.hideMainWindowPasteText(res.stdout);\n      return;\n    }\n    return JSON.stringify(res);\n  } catch (ex) {\n    return (ex as object).toString();\n  }\n};\n"
  },
  {
    "path": "uTools/Open ChatGPT/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/Open ChatGPT/script/src/main.ts",
    "content": "import { askChatGPT as askOpenai } from '@share/utils/uTools';\nimport { AskChatGPT } from '@share/uTools/webviewBaseController';\n\nexport const bootstrap = async (scriptFile?: string) => {\n  utools.redirect(['lowcode', 'lowcode'], {\n    type: 'text',\n    data: JSON.stringify({\n      scriptFile,\n      route: '/chat',\n    }),\n  });\n};\n\n// 给页面调用的\nexport const askChatGPT: AskChatGPT = (data) =>\n  askOpenai({ ...data, model: undefined });\n"
  },
  {
    "path": "uTools/Open ChatGPT-获取命令行命令/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/Open ChatGPT-获取命令行命令/script/src/main.ts",
    "content": "import { clipboard } from 'electron';\nimport { askChatGPT as askOpenai } from '@share/utils/uTools';\n\nexport const bootstrap = async (scriptFile?: string) => {\n  const text = clipboard.readText();\n  let platform = utools.isWindows() ? 'windows' : 'mac';\n  if (utools.isLinux()) {\n    platform = 'linux';\n  }\n  if (!text) {\n    utools.showNotification('请先复制内容');\n    return;\n  }\n\n  utools.redirect(['lowcode', 'lowcode'], {\n    type: 'text',\n    data: JSON.stringify({\n      scriptFile,\n      route: '/chat',\n      content: `${platform} 平台下， ${text}，返回可执行的命令即可，不要带多余的信息`,\n    }),\n  });\n};\n\ntype LLMMessage = (\n  | {\n      role: 'system';\n      content: string;\n    }\n  | {\n      role: 'user';\n      content:\n        | string\n        | (\n            | {\n                type: 'image_url';\n                image_url: { url: string };\n              }\n            | { type: 'text'; text: string }\n          )[];\n    }\n)[];\n// 给页面调用的\nexport const askChatGPT = async (data: {\n  messages: LLMMessage;\n  handleChunk: (chunck: string) => void;\n  scriptFile: string;\n}) => {\n  const content = await askOpenai({\n    messages: data.messages,\n    handleChunk: data.handleChunk,\n  });\n  return content;\n};\n"
  },
  {
    "path": "uTools/Open Tldraw/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/Open Tldraw/script/src/main.ts",
    "content": "import { askChatGPT as askOpenai } from '@share/utils/uTools';\nimport { AskChatGPT } from '@share/uTools/webviewBaseController';\n\nexport const bootstrap = async (scriptFile?: string) => {\n  utools.redirect(['lowcode', 'lowcode'], {\n    type: 'text',\n    data: JSON.stringify({ scriptFile, route: '/tldraw' }),\n  });\n};\n\n// 给页面调用的\nexport const askChatGPT: AskChatGPT = (data) =>\n  askOpenai({ ...data, model: undefined });\n"
  },
  {
    "path": "uTools/TS 类型新增字段 - 根据 YAPI 文档字段格式/prompt.md",
    "content": "```\ndateType\ninteger\n非必须\n日期类型 0~录入时间、1~成交时间、2~结案时间、3~申佣时间\n```\n\n根据上面的内容生成如下 TS 代码\n\n```js\n/** 日期类型 0~录入时间、1~成交时间、2~结案时间、3~申佣时间 */\ndateType: number;\n```\n\n按照上面的规则，请根据下面的内容生成代码：\n\n```\n```\n\n\n"
  },
  {
    "path": "uTools/TS 类型新增字段 - 根据 YAPI 文档字段格式/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/TS 类型新增字段 - 根据 YAPI 文档字段格式/script/src/main.ts",
    "content": "import { askChatGPT as askOpenai } from '@share/utils/uTools';\nimport { AskChatGPT } from '@share/uTools/webviewBaseController';\nimport { clipboard } from 'electron';\n\nexport const bootstrap = async (scriptFile?: string) => {\n  const clipboardText = clipboard.readText() || '';\n  if (!clipboardText) {\n    return '请复制内容';\n  }\n  const requestPrompt = `\n\\`\\`\\`\ndateType\ninteger\n非必须\n日期类型 0~录入时间、1~成交时间、2~结案时间、3~申佣时间\n\\`\\`\\`\n\n根据上面的内容生成如下 TS 代码\n\n\\`\\`\\`js\n/** 日期类型 0~录入时间、1~成交时间、2~结案时间、3~申佣时间 */\ndateType: number;\n\\`\\`\\`\n\n按照上面的规则，请根据下面的内容生成代码：\n\n\\`\\`\\`\n${clipboardText\n  .split(/\\t|\\n/)\n  .filter((s) => s)\n  .join('\\n')}\n\\`\\`\\`  \n`;\n  // const content = await askOpenai({\n  //   messages: [{ role: 'user', content: requestPrompt }],\n  //   handleChunk: () => {},\n  // });\n  // utools.outPlugin();\n  // utools.hideMainWindowPasteText(\n  //   content.content.replace(/```js/g, '').replace(/```/g, ''),\n  // );\n  utools.redirect(['lowcode', 'lowcode'], {\n    type: 'text',\n    data: JSON.stringify({\n      scriptFile,\n      route: '/chat',\n      content: requestPrompt,\n    }),\n  });\n};\n\n// 给页面调用的\nexport const askChatGPT: AskChatGPT = async (data) => {\n  const res = await askOpenai({ ...data, model: undefined });\n  setTimeout(() => {\n    utools.outPlugin();\n    utools.hideMainWindowPasteText(\n      res.content.replace(/```js/g, '').replace(/```/g, ''),\n    );\n  }, 2000);\n  return res;\n};\n"
  },
  {
    "path": "uTools/TS 类型新增字段 - 根据 YAPI 文档字段格式 - 截图/README.md",
    "content": "```html\n<html>\n  <body>\n    <table>\n      <tbody>\n        <tr>\n          <td>provinceName</td>\n          <td>string</td>\n          <td>非必须</td>\n          <td>省份</td>\n          <td></td>\n        </tr>\n        <tr>\n          <td>provinceCode</td>\n          <td>string</td>\n          <td>非必须</td>\n          <td></td>\n          <td>省份编码</td>\n        </tr>\n        <tr>\n          <td>cityName</td>\n          <td>string</td>\n          <td>非必须</td>\n          <td></td>\n          <td>城市</td>\n        </tr>\n      </tbody>\n    </table>\n  </body>\n</html>\n```\n\n根据上面的内容生成如下 TS 代码\n\n```js\n/** 省份 */\nprovinceName: string;\n/** 省份编码 */\nprovinceCode: string;\n/** 城市 */\ncityName: string;\n```\n\n按照上面的规则，请根据下面的内容生成代码：\n\n```html\n\n```\n"
  },
  {
    "path": "uTools/TS 类型新增字段 - 根据 YAPI 文档字段格式 - 截图/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/TS 类型新增字段 - 根据 YAPI 文档字段格式 - 截图/script/src/main.ts",
    "content": "import { AskChatGPT } from '@share/uTools/webviewBaseController';\nimport { askChatGPT as askOpenai, ocr } from '@share/utils/uTools';\nimport { clipboard } from 'electron';\n\nexport const bootstrap = async (scriptFile?: string) => {\n  const availableFormats = clipboard.availableFormats('clipboard');\n  if (!availableFormats.some((s) => s.includes('image'))) {\n    return '剪贴板里没有截图';\n  }\n  const base64 = clipboard.readImage('clipboard').toDataURL();\n  const ocrRes = await ocr({ base64, model: 'structure_table' });\n\n  if (ocrRes.result?.texts && ocrRes.result.texts[0]) {\n    const requestPrompt = `\n\\`\\`\\`html\n<html>\n  <body>\n    <table>\n      <tbody>\n        <tr>\n          <td>provinceName</td>\n          <td>string</td>\n          <td>非必须</td>\n          <td>省份</td>\n          <td></td>\n        </tr>\n        <tr>\n          <td>provinceCode</td>\n          <td>string</td>\n          <td>非必须</td>\n          <td></td>\n          <td>省份编码</td>\n        </tr>\n        <tr>\n          <td>cityName</td>\n          <td>string</td>\n          <td>非必须</td>\n          <td></td>\n          <td>城市</td>\n        </tr>\n      </tbody>\n    </table>\n  </body>\n</html>\n\\`\\`\\`\n\n根据上面的内容生成如下 TS 代码\n\n\\`\\`\\`js\n/** 省份 */\nprovinceName: string;\n/** 省份编码 */\nprovinceCode: string;\n/** 城市 */\ncityName: string;\n\\`\\`\\`\n\n按照上面的规则，请根据下面的内容生成代码：\n\n\\`\\`\\`html\n${ocrRes.result.texts[0]}\n\\`\\`\\`\n\n`;\n    // const content = await askOpenai({\n    //   messages: [{ role: 'user', content: requestPrompt }],\n    //   handleChunk: () => {},\n    // });\n    // utools.outPlugin();\n    // utools.hideMainWindowPasteText(\n    //   content.content.replace(/```js/g, '').replace(/```/g, ''),\n    // );\n    utools.redirect(['lowcode', 'lowcode'], {\n      type: 'text',\n      data: JSON.stringify({\n        scriptFile,\n        route: '/chat',\n        content: requestPrompt,\n      }),\n    });\n  }\n};\n\n// 给页面调用的\nexport const askChatGPT: AskChatGPT = async (data) => {\n  const res = await askOpenai({ ...data, model: undefined });\n  setTimeout(() => {\n    utools.outPlugin();\n    utools.hideMainWindowPasteText(\n      res.content.replace(/```js/g, '').replace(/```/g, ''),\n    );\n  }, 2000);\n  return res;\n};\n"
  },
  {
    "path": "uTools/vscode 选中的文件夹/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/vscode 选中的文件夹/script/src/main.ts",
    "content": "import { clipboard } from 'electron';\nimport { getShareData } from '@share/utils/shareData';\n\nexport const bootstrap = async (scriptFile?: string) => {\n  const data = getShareData();\n  return data.selectedFolder || '';\n};\n"
  },
  {
    "path": "uTools/中文翻译英文/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/中文翻译英文/script/src/main.ts",
    "content": "import { clipboard } from 'electron';\nimport { createChatCompletion } from '@share/LLM/openaiV2';\n\nexport const bootstrap = async () => {\n  const text = clipboard.readText();\n  if (!text) {\n    utools.showNotification('请先复制内容');\n    return;\n  }\n  const res = await createChatCompletion({\n    messages: [\n      {\n        role: 'system',\n        content: `你是一个翻译家，你的目标是把中文翻译成英文，请翻译时不要带翻译腔，而是要翻译得自然、流畅和地道，使用优美和高雅的表达方式。请翻译下面用户输入的内容`,\n      },\n      {\n        role: 'user',\n        content: text,\n      },\n    ],\n  });\n  return res;\n};\n"
  },
  {
    "path": "uTools/动态表单 demo/config/config.json",
    "content": "{\n\t\"scripts\": [\n\t\t{\n\t\t\t\"method\": \"initFiltersFromImage\",\n\t\t\t\"remark\": \"使用 OCR 识别查询条件截图内容\"\n\t\t},\n\t\t{\n\t\t\t\"method\": \"initFiltersFromText\",\n\t\t\t\"remark\": \"使用文本初始化查询条件\"\n\t\t},\n\t\t{\n\t\t\t\"method\": \"initColumnsFromText\",\n\t\t\t\"remark\": \"使用文本初始化表格\"\n\t\t},\n\t\t{\n\t\t\t\"method\": \"openChatGPT\",\n\t\t\t\"remark\": \"使用 ChatGPT 翻译模版数据里的指定中文字段\"\n\t\t},\n\t\t{\n\t\t\t\"method\": \"generateCode\",\n\t\t\t\"remark\": \"生成代码\"\n\t\t}\n\t]\n}"
  },
  {
    "path": "uTools/动态表单 demo/config/model.json",
    "content": "{\n  \"filters\": [],\n  \"columns\": [],\n  \"pagination\": {\n    \"show\": true,\n    \"page\": \"page\",\n    \"size\": \"size\",\n    \"total\": \"result.total\"\n  },\n  \"includeModifyModal\": false,\n  \"fetchName\": \"fetchTableList\",\n  \"result\": \"[\\\"result\\\"][\\\"records\\\"]\",\n  \"serviceName\": \"getTableList\"\n}\n"
  },
  {
    "path": "uTools/动态表单 demo/config/schema.json",
    "content": "{\n\t\"type\": \"page\",\n\t\"body\": [\n\t\t{\n\t\t\t\"type\": \"form\",\n\t\t\t\"title\": \"\",\n\t\t\t\"body\": [\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"combo\",\n\t\t\t\t\t\"label\": \"查询条件\",\n\t\t\t\t\t\"name\": \"filters\",\n\t\t\t\t\t\"multiple\": true,\n\t\t\t\t\t\"addable\": true,\n\t\t\t\t\t\"removable\": true,\n\t\t\t\t\t\"removableMode\": \"icon\",\n\t\t\t\t\t\"addBtn\": {\n\t\t\t\t\t\t\"label\": \"新增\",\n\t\t\t\t\t\t\"icon\": \"fa fa-plus\",\n\t\t\t\t\t\t\"level\": \"primary\",\n\t\t\t\t\t\t\"size\": \"sm\",\n\t\t\t\t\t\t\"id\": \"u:47ecb9e15ff1\"\n\t\t\t\t\t},\n\t\t\t\t\t\"items\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"name\": \"key\",\n\t\t\t\t\t\t\t\"placeholder\": \"字段名\",\n\t\t\t\t\t\t\t\"id\": \"u:25b0c7b5e5a0\",\n\t\t\t\t\t\t\t\"label\": \"字段名（key）\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"label\": \"label\",\n\t\t\t\t\t\t\t\"name\": \"label\",\n\t\t\t\t\t\t\t\"id\": \"u:6496cac4f4b8\",\n\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\"name\": \"component\",\n\t\t\t\t\t\t\t\"placeholder\": \"选项\",\n\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"label\": \"input\",\n\t\t\t\t\t\t\t\t\t\"value\": \"input\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"label\": \"select\",\n\t\t\t\t\t\t\t\t\t\"value\": \"select\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"id\": \"u:995915eabcca\",\n\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\"label\": \"组件\",\n\t\t\t\t\t\t\t\"value\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"label\": \"placeholder\",\n\t\t\t\t\t\t\t\"name\": \"placeholder\",\n\t\t\t\t\t\t\t\"id\": \"u:d7f1a8a39449\",\n\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\t\"id\": \"u:186f183e9320\",\n\t\t\t\t\t\"strictMode\": false,\n\t\t\t\t\t\"syncFields\": [],\n\t\t\t\t\t\"tabsMode\": true,\n\t\t\t\t\t\"draggable\": true,\n\t\t\t\t\t\"draggableTip\": \"可拖动排序\",\n\t\t\t\t\t\"tabsStyle\": \"line\",\n\t\t\t\t\t\"tabsLabelTpl\": \"表单项${index+1}\",\n\t\t\t\t\t\"multiLine\": true,\n\t\t\t\t\t\"noBorder\": false\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"combo\",\n\t\t\t\t\t\"label\": \"表格\",\n\t\t\t\t\t\"name\": \"columns\",\n\t\t\t\t\t\"multiple\": true,\n\t\t\t\t\t\"addable\": true,\n\t\t\t\t\t\"removable\": true,\n\t\t\t\t\t\"removableMode\": \"button\",\n\t\t\t\t\t\"addBtn\": {\n\t\t\t\t\t\t\"label\": \"新增\",\n\t\t\t\t\t\t\"icon\": \"fa fa-plus\",\n\t\t\t\t\t\t\"level\": \"primary\",\n\t\t\t\t\t\t\"size\": \"sm\",\n\t\t\t\t\t\t\"id\": \"u:1e8070edc3d3\"\n\t\t\t\t\t},\n\t\t\t\t\t\"items\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"name\": \"title\",\n\t\t\t\t\t\t\t\"id\": \"u:152dd82b82f9\",\n\t\t\t\t\t\t\t\"label\": \"title\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"label\": \"dataIndex\",\n\t\t\t\t\t\t\t\"name\": \"dataIndex\",\n\t\t\t\t\t\t\t\"id\": \"u:ecc7298e0550\",\n\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"label\": \"key\",\n\t\t\t\t\t\t\t\"name\": \"key\",\n\t\t\t\t\t\t\t\"id\": \"u:fbaa95c3f15d\",\n\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"label\": \"width\",\n\t\t\t\t\t\t\t\"name\": \"width\",\n\t\t\t\t\t\t\t\"id\": \"u:b143127e097b\",\n\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\"label\": \"自定义插槽\",\n\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\"name\": \"slot\",\n\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\"id\": \"u:ee1ce1faee0b\",\n\t\t\t\t\t\t\t\"value\": false\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\t\"id\": \"u:9b9fb0cf38f9\",\n\t\t\t\t\t\"strictMode\": true,\n\t\t\t\t\t\"syncFields\": [],\n\t\t\t\t\t\"tabsMode\": true,\n\t\t\t\t\t\"draggable\": true,\n\t\t\t\t\t\"draggableTip\": \"可拖动排序\",\n\t\t\t\t\t\"tabsStyle\": \"line\",\n\t\t\t\t\t\"deleteBtn\": {\n\t\t\t\t\t\t\"label\": \"删除\",\n\t\t\t\t\t\t\"level\": \"default\"\n\t\t\t\t\t},\n\t\t\t\t\t\"tabsLabelTpl\": \"列${index+1}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"fieldset\",\n\t\t\t\t\t\"title\": \"分页参数\",\n\t\t\t\t\t\"collapsable\": true,\n\t\t\t\t\t\"body\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\"label\": \"是否分页\",\n\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\"name\": \"pagination.show\",\n\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\"id\": \"u:6c70041d5143\",\n\t\t\t\t\t\t\t\"value\": true,\n\t\t\t\t\t\t\t\"className\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"label\": \"查询接口页数参数字段名\",\n\t\t\t\t\t\t\t\"name\": \"pagination.page\",\n\t\t\t\t\t\t\t\"id\": \"u:cbbf6853cf64\",\n\t\t\t\t\t\t\t\"value\": \"page\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"label\": \"查询接口每页数据行数参数字段名\",\n\t\t\t\t\t\t\t\"name\": \"pagination.size\",\n\t\t\t\t\t\t\t\"id\": \"u:a8fae66fa927\",\n\t\t\t\t\t\t\t\"value\": \"size\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"label\": \"接口返回总数据量字段 PATH\",\n\t\t\t\t\t\t\t\"name\": \"pagination.total\",\n\t\t\t\t\t\t\t\"id\": \"u:e1cd979c7ee8\",\n\t\t\t\t\t\t\t\"value\": \"result.total\",\n\t\t\t\t\t\t\t\"themeCss\": {\n\t\t\t\t\t\t\t\t\"inputControlClassName\": {\n\t\t\t\t\t\t\t\t\t\"padding-and-margin:default\": {\n\t\t\t\t\t\t\t\t\t\t\"marginBottom\": \"\",\n\t\t\t\t\t\t\t\t\t\t\"marginTop\": \"\",\n\t\t\t\t\t\t\t\t\t\t\"marginRight\": \"\",\n\t\t\t\t\t\t\t\t\t\t\"marginLeft\": \"\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\t\"id\": \"u:0f1bd8fc2f2b\",\n\t\t\t\t\t\"collapsed\": true,\n\t\t\t\t\t\"headingClassName\": \"\",\n\t\t\t\t\t\"bodyClassName\": \"p\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"fieldset\",\n\t\t\t\t\t\"title\": \"请求方法\",\n\t\t\t\t\t\"collapsable\": true,\n\t\t\t\t\t\"body\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"label\": \"请求名称\",\n\t\t\t\t\t\t\t\"name\": \"fetchName\",\n\t\t\t\t\t\t\t\"id\": \"u:a3e712484fae\",\n\t\t\t\t\t\t\t\"value\": \"fetchTableList\",\n\t\t\t\t\t\t\t\"description\": \"追加了YAPI数据则不使用此参数\",\n\t\t\t\t\t\t\t\"themeCss\": {\n\t\t\t\t\t\t\t\t\"labelClassName\": {\n\t\t\t\t\t\t\t\t\t\"padding-and-margin:default\": {\n\t\t\t\t\t\t\t\t\t\t\"marginTop\": \"\",\n\t\t\t\t\t\t\t\t\t\t\"marginRight\": \"\",\n\t\t\t\t\t\t\t\t\t\t\"marginBottom\": \"\",\n\t\t\t\t\t\t\t\t\t\t\"marginLeft\": \"\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"labelClassName\": \"labelClassName-a3e712484fae\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"label\": \"接口数据字段 PATH\",\n\t\t\t\t\t\t\t\"name\": \"result\",\n\t\t\t\t\t\t\t\"id\": \"u:8c082acf7db2\",\n\t\t\t\t\t\t\t\"value\": \"[\\\"result\\\"][\\\"records\\\"]\",\n\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\"label\": \"service方法名\",\n\t\t\t\t\t\t\t\"name\": \"serviceName\",\n\t\t\t\t\t\t\t\"id\": \"u:cfbbdd07366b\",\n\t\t\t\t\t\t\t\"value\": \"getTableList\",\n\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\t\"id\": \"u:382f8cdf59a6\",\n\t\t\t\t\t\"collapsed\": true,\n\t\t\t\t\t\"className\": \"\",\n\t\t\t\t\t\"headingClassName\": \"\",\n\t\t\t\t\t\"bodyClassName\": \"p-r p-l p-b\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"fieldset\",\n\t\t\t\t\t\"title\": \"新增/编辑弹框\",\n\t\t\t\t\t\"collapsable\": true,\n\t\t\t\t\t\"body\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\"label\": \"是否包含弹框\",\n\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\"name\": \"includeModifyModal\",\n\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\"id\": \"u:03957070af9e\",\n\t\t\t\t\t\t\t\"value\": false\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"combo\",\n\t\t\t\t\t\t\t\"label\": \"表单项\",\n\t\t\t\t\t\t\t\"name\": \"modifyModal.formItems\",\n\t\t\t\t\t\t\t\"multiple\": true,\n\t\t\t\t\t\t\t\"addable\": true,\n\t\t\t\t\t\t\t\"removable\": true,\n\t\t\t\t\t\t\t\"removableMode\": \"icon\",\n\t\t\t\t\t\t\t\"strictMode\": false,\n\t\t\t\t\t\t\t\"addBtn\": {\n\t\t\t\t\t\t\t\t\"label\": \"新增\",\n\t\t\t\t\t\t\t\t\"icon\": \"fa fa-plus\",\n\t\t\t\t\t\t\t\t\"level\": \"primary\",\n\t\t\t\t\t\t\t\t\"size\": \"sm\",\n\t\t\t\t\t\t\t\t\"id\": \"u:86cc27b6a663\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"items\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"key\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:62cc1cf36c73\",\n\t\t\t\t\t\t\t\t\t\"label\": \"字段名（key）\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\"name\": \"type\",\n\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"string\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"number\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"number\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"boolean\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"Dayjs\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"Dayjs\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"string[]\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"string[]\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"number[]\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"number[]\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"boolean[]\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"boolean[]\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"[Dayjs,Dayjs]\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"[Dayjs,Dayjs]\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"id\": \"u:b165c75e5e1a\",\n\t\t\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\t\t\"label\": \"字段类型\",\n\t\t\t\t\t\t\t\t\t\"value\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"字段可选\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"optional\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:68fc4c85fb03\",\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"字段名字后加?\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\"name\": \"defaultValue\",\n\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"\\\"\\\"\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"\\\"\\\"\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"false\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"false\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"true\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"true\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"0\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"0\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"undefined\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"undefined\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"[]\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"[]\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"id\": \"u:379ea92fb3c6\",\n\t\t\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\t\t\"label\": \"默认值\",\n\t\t\t\t\t\t\t\t\t\"value\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\"name\": \"component\",\n\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"input\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"input\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"input-password\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"input-password\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"input-number\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"input-number\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"textarea\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"textarea\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"select\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"select\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"radio-group\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"radio-group\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"checkbox-group\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"checkbox-group\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"switch\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"switch\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"date-picker\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"date-picker\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"time-ticker\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"time-picker\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"range-picker\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"range-picker\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"transfer\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"transfer\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"id\": \"u:7932ea3b05da\",\n\t\t\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\t\t\"label\": \"组件\",\n\t\t\t\t\t\t\t\t\t\"value\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"label\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:5bb237f20098\",\n\t\t\t\t\t\t\t\t\t\"label\": \"label\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"placeholder\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:580898257491\",\n\t\t\t\t\t\t\t\t\t\"label\": \"placeholder\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"required\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"required\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:559dbdbb01da\",\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"验证规则加required\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"message\",\n\t\t\t\t\t\t\t\t\t\"id\": \"u:55013279d659\",\n\t\t\t\t\t\t\t\t\t\"label\": \"校验失败 message\",\n\t\t\t\t\t\t\t\t\t\"value\": \"不能为空\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"更多组件配置\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"showMore\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:67e0cb5b7496\",\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"labelInValue\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"labelInValue\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"id\": \"u:7fd6f1b233d9\",\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"是否把每个选项的 label 包装到 value 中\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'select'}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\"name\": \"mode\",\n\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"multiple\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"multiple\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"tags\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"tags\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\t\t\"label\": \"mode\",\n\t\t\t\t\t\t\t\t\t\"value\": \"\",\n\t\t\t\t\t\t\t\t\t\"description\": \"设置 Select 的模式为多选或标签\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'select'}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"optionFilterProp\",\n\t\t\t\t\t\t\t\t\t\"label\": \"optionFilterProp\",\n\t\t\t\t\t\t\t\t\t\"description\": \"搜索时过滤对应的 option 属性\",\n\t\t\t\t\t\t\t\t\t\"value\": \"label\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'select'}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"showSearch\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"showSearch\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"使单选模式可搜索\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'select'}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"hideArrow\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"hideArrow\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"是否隐藏下拉小箭头\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'select'}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"maxlength\",\n\t\t\t\t\t\t\t\t\t\"label\": \"maxlength\",\n\t\t\t\t\t\t\t\t\t\"description\": \"最大长度\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'input' && modifyModal.formItems[index].component !== 'input-password' && modifyModal.formItems[index].component !== 'textarea')}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"showCount\",\n\t\t\t\t\t\t\t\t\t\"option\": \"\",\n\t\t\t\t\t\t\t\t\t\"name\": \"showCount\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"是否展示字数\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'input' && modifyModal.formItems[index].component !== 'input-password' && modifyModal.formItems[index].component !== 'textarea')}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"max\",\n\t\t\t\t\t\t\t\t\t\"label\": \"max\",\n\t\t\t\t\t\t\t\t\t\"description\": \"最大值\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'input-number'}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"min\",\n\t\t\t\t\t\t\t\t\t\"label\": \"min\",\n\t\t\t\t\t\t\t\t\t\"description\": \"最小值\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'input-number'}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"step\",\n\t\t\t\t\t\t\t\t\t\"label\": \"step\",\n\t\t\t\t\t\t\t\t\t\"description\": \"每次改变步数，可以为小数\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'input-number'}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"checkedChildren\",\n\t\t\t\t\t\t\t\t\t\"label\": \"checkedChildren\",\n\t\t\t\t\t\t\t\t\t\"description\": \"选中时的内容\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'switch'}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"unCheckedChildren\",\n\t\t\t\t\t\t\t\t\t\"label\": \"unCheckedChildren\",\n\t\t\t\t\t\t\t\t\t\"description\": \"非选中时的内容\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'switch'}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"checkedValue\",\n\t\t\t\t\t\t\t\t\t\"label\": \"checkedValue\",\n\t\t\t\t\t\t\t\t\t\"description\": \"选中时的值\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'switch'}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"input-text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"unCheckedValue\",\n\t\t\t\t\t\t\t\t\t\"label\": \"unCheckedValue\",\n\t\t\t\t\t\t\t\t\t\"description\": \"非选中时的值\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || modifyModal.formItems[index].component !== 'switch'}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"select\",\n\t\t\t\t\t\t\t\t\t\"name\": \"picker\",\n\t\t\t\t\t\t\t\t\t\"options\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"date\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"date\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"week\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"week\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"month\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"month\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"quarter\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"quarter\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"label\": \"year\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"year\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"multiple\": false,\n\t\t\t\t\t\t\t\t\t\"label\": \"picker\",\n\t\t\t\t\t\t\t\t\t\"description\": \"设置选择器类型\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'date-picker' && modifyModal.formItems[index].component !== 'range-picker')}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"showTime\",\n\t\t\t\t\t\t\t\t\t\"name\": \"showTime\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"增加时间选择功能\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'date-picker' && modifyModal.formItems[index].component !== 'range-picker' || modifyModal.formItems[index].picker !== 'date')}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"showNow\",\n\t\t\t\t\t\t\t\t\t\"name\": \"showNow\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"当设定了 showTime 的时候，面板是否显示“此刻”按钮\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'date-picker' && modifyModal.formItems[index].component !== 'range-picker' || modifyModal.formItems[index].picker !== 'date')}\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"switch\",\n\t\t\t\t\t\t\t\t\t\"label\": \"showToday\",\n\t\t\t\t\t\t\t\t\t\"name\": \"showToday\",\n\t\t\t\t\t\t\t\t\t\"falseValue\": false,\n\t\t\t\t\t\t\t\t\t\"trueValue\": true,\n\t\t\t\t\t\t\t\t\t\"value\": false,\n\t\t\t\t\t\t\t\t\t\"description\": \"是否展示“今天”按钮\",\n\t\t\t\t\t\t\t\t\t\"hiddenOn\": \"${!modifyModal.formItems[index].showMore || (modifyModal.formItems[index].component !== 'date-picker' && modifyModal.formItems[index].component !== 'range-picker' || modifyModal.formItems[index].picker !== 'date')}\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"syncFields\": [],\n\t\t\t\t\t\t\t\"tabsMode\": true,\n\t\t\t\t\t\t\t\"draggable\": true,\n\t\t\t\t\t\t\t\"draggableTip\": \"可拖动排序\",\n\t\t\t\t\t\t\t\"tabsStyle\": \"line\",\n\t\t\t\t\t\t\t\"tabsLabelTpl\": \"表单项${index+1}\",\n\t\t\t\t\t\t\t\"multiLine\": true,\n\t\t\t\t\t\t\t\"noBorder\": false,\n\t\t\t\t\t\t\t\"hiddenOn\": \"${!includeModifyModal}\"\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\t\"bodyClassName\": \"p\",\n\t\t\t\t\t\"collapsed\": true\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"submitText\": \"\"\n\t\t}\n\t],\n\t\"pullRefresh\": {\n\t\t\"disabled\": true\n\t},\n\t\"regions\": [\n\t\t\"body\"\n\t],\n\t\"style\": {\n\t\t\"boxShadow\": \" 0px 0px 0px 0px transparent\"\n\t},\n\t\"asideResizor\": false\n}"
  },
  {
    "path": "uTools/动态表单 demo/config/schema.ts",
    "content": "export type PageConfig = {\n  filters: {\n    component: string;\n    /**\n     * @description 翻译成英文，驼峰格式\n     * @type {string}\n     */\n    key: string;\n    /**\n     * @description 保持原始内容，不要翻译\n     * @type {string}\n     */\n    label: string;\n    /**\n     * @description 保持原始内容，不要翻译\n     * @type {string}\n     */\n    placeholder: string;\n  }[];\n  columns: {\n    slot: boolean;\n    /**\n     * @description 保持原始内容，不要翻译\n     * @type {string}\n     */\n    title: string;\n    /**\n     * @description 翻译成英文，驼峰格式\n     * @type {string}\n     */\n    dataIndex: string;\n    /**\n     * @description 翻译成英文，驼峰格式\n     * @type {string}\n     */\n    key: string;\n  }[];\n  pagination: {\n    show: boolean;\n    page: string;\n    size: string;\n    total: string;\n  };\n  includeModifyModal: boolean;\n  fetchName: string;\n  result: string;\n  serviceName: string;\n};\n"
  },
  {
    "path": "uTools/动态表单 demo/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/动态表单 demo/script/src/controller.ts",
    "content": "import path from 'path';\nimport * as fs from 'fs-extra';\nimport * as execa from 'execa';\nimport * as ejs from 'ejs';\nimport axios from 'axios';\nimport { clipboard } from 'electron';\nimport { generalBasic } from '@share/BaiduOCR/index';\nimport { renderEjsTemplates } from '@share/utils/ejs';\nimport { typescriptToMock } from '@share/utils/platformIndependent/json';\nimport { getShareData } from '@share/utils/shareData';\nimport { MethodHandle } from '@share/uTools/webviewBaseController';\nimport { getBlockJsonValidSchema } from '@share/utils/uTools';\n\nexport const initFiltersFromImage: MethodHandle = async (data) => {\n  const availableFormats = clipboard.availableFormats('clipboard');\n  if (!availableFormats.some((s) => s.includes('image'))) {\n    throw new Error('剪贴板里没有截图');\n  }\n  const base64 = clipboard.readImage('clipboard').toDataURL();\n  const ocrRes = await generalBasic({ image: base64 });\n  return {\n    updateModelImmediately: false,\n    model: data.model,\n    onlyUpdateParams: true,\n    params: ocrRes.words_result.map((s) => s.words).join('\\r\\n'),\n  };\n};\n\nexport const initFiltersFromText: MethodHandle = async (data) => {\n  const filters = data.params\n    .replace(/\\r\\n/g, '\\n')\n    .replace(/\\r/g, '\\n')\n    .split('\\n');\n  const formatedFilters = filters.map((item) => {\n    const s = item.replace(/：|：/g, ':').split(':');\n    return {\n      component: (s[1] || '').indexOf('选择') > -1 ? 'select' : 'input',\n      key: s[0].trim(),\n      label: s[0].trim(),\n      placeholder: s[1] || '',\n    };\n  });\n  return {\n    updateModelImmediately: false,\n    onlyUpdateParams: false,\n    params: '',\n    model: { ...data.model, filters: formatedFilters },\n  };\n};\n\nexport const initColumnsFromText: MethodHandle = async (data) => {\n  const columns = data.params\n    .replace(/\\r\\n/g, '\\n')\n    .replace(/\\r/g, '\\n')\n    .split('\\n');\n  const formatedColumns = columns.map((s) => ({\n    slot: false,\n    title: s,\n    dataIndex: s,\n    key: s,\n  }));\n  return {\n    updateModelImmediately: false,\n    onlyUpdateParams: false,\n    params: '',\n    model: { ...data.model, columns: formatedColumns },\n  };\n};\n\nexport const openChatGPT: MethodHandle = async (data) => {\n  const schema = getBlockJsonValidSchema(data.scriptFile);\n  const clipboardText = JSON.stringify(data.model);\n  const typeName = 'PageConfig';\n  const requestPrompt =\n    `You are a service that translates user requests into JSON objects of type \"${typeName}\" according to the following TypeScript definitions:\\n` +\n    `\\`\\`\\`\\n${schema}\\`\\`\\`\\n` +\n    `The following is a user request:\\n` +\n    `\"\"\"\\n${clipboardText}\\n\"\"\"\\n` +\n    `The following is the user request translated into a JSON object with 2 spaces of indentation and no properties with the value undefined:\\n`;\n  return {\n    updateModelImmediately: true,\n    onlyUpdateParams: false,\n    params: '',\n    showChat: true,\n    chatContent: requestPrompt,\n    model: data.model,\n  };\n};\n\nexport const generateCode: MethodHandle = async (data) => {\n  const { selectedFolder, activeWindow } = getShareData();\n  const tempWorkPath = path.join(activeWindow || '', '.lowcode');\n  const blockPath = path.join(\n    data.scriptFile\n      .replace('/script/src/mainBundle', '')\n      .replace('/script/src/main', ''),\n  );\n  fs.copySync(blockPath, tempWorkPath);\n  try {\n    await renderEjsTemplates(\n      {\n        ...data.model,\n        createBlockPath: path.join(selectedFolder || '').replace(/\\\\/g, '/'),\n      },\n      path.join(tempWorkPath, 'src'),\n    );\n\n    // #region 更新 mock 服务\n    const mockType = fs\n      .readFileSync(path.join(tempWorkPath, 'src', 'temp.mock.type').toString())\n      .toString();\n    fs.removeSync(path.join(tempWorkPath, 'src', 'temp.mock.type'));\n    const { mockCode, mockData } = typescriptToMock(mockType);\n    const mockTemplate = fs\n      .readFileSync(\n        path.join(tempWorkPath, 'src', 'temp.mock.script').toString(),\n      )\n      .toString();\n    fs.removeSync(path.join(tempWorkPath, 'src', 'temp.mock.script'));\n    const mockScript = ejs.render(mockTemplate, {\n      ...data.model,\n      mockCode,\n      mockData,\n      createBlockPath: selectedFolder?.replace(':', ''),\n    });\n    const mockProjectPathRes = await axios\n      .get('http://localhost:3000/mockProjectPath', { timeout: 1000 })\n      .catch(() => {\n        // window.showInformationMessage(\n        //   '获取 mock 项目路径失败，跳过更新 mock 服务',\n        // );\n      });\n    if (mockProjectPathRes?.data.result) {\n      const projectName = activeWindow?.replace(/\\\\/g, '/').split('/').pop();\n      const mockRouteFile = path.join(\n        mockProjectPathRes.data.result,\n        `${projectName}.js`,\n      );\n      let mockFileContent = `\n\t import KoaRouter from 'koa-router';\n\t import proxy from '../middleware/Proxy';\n\t import { delay } from '../lib/util';\n\n\t const Mock = require('mockjs');\n\n\t const { Random } = Mock;\n\n\t const router = new KoaRouter();\n\t router{{mockScript}}\n\t module.exports = router;\n\t `;\n\n      if (fs.existsSync(mockRouteFile)) {\n        mockFileContent = fs.readFileSync(mockRouteFile).toString().toString();\n        const index = mockFileContent.lastIndexOf(')') + 1;\n        mockFileContent = `${mockFileContent.substring(\n          0,\n          index,\n        )}{{mockScript}}\\n${mockFileContent.substring(index)}`;\n      }\n      mockFileContent = mockFileContent.replace(/{{mockScript}}/g, mockScript);\n      fs.writeFileSync(mockRouteFile, mockFileContent);\n      try {\n        execa.sync('node', [\n          path.join(\n            mockProjectPathRes.data.result\n              .replace(/\\\\/g, '/')\n              .replace('/src/routes', ''),\n            '/node_modules/eslint/bin/eslint.js',\n          ),\n          mockRouteFile,\n          '--resolve-plugins-relative-to',\n          mockProjectPathRes.data.result\n            .replace(/\\\\/g, '/')\n            .replace('/src/routes', ''),\n          '--fix',\n        ]);\n      } catch (err) {\n        console.log(err);\n      }\n      // #endregion\n    }\n  } catch (ex) {\n    fs.removeSync(tempWorkPath);\n    throw ex;\n  }\n\n  fs.copySync(path.join(tempWorkPath, 'src'), path.join(selectedFolder || ''));\n  fs.removeSync(tempWorkPath);\n\n  return {\n    updateModelImmediately: false,\n    model: data.model,\n    onlyUpdateParams: true,\n    params: `代码生成目录：${selectedFolder}`,\n  };\n};\n"
  },
  {
    "path": "uTools/动态表单 demo/script/src/main.ts",
    "content": "import { clipboard } from 'electron';\nimport {\n  AskChatGPTForDynamicFormPageWebviewData,\n  MethodHandle,\n  baseAskChatGPTForDynamicFormPage,\n} from '@share/uTools/webviewBaseController';\nimport * as controller from './controller';\n\nexport const bootstrap = async (scriptFile?: string) => {\n  utools.redirect(['lowcode', 'lowcode'], {\n    type: 'text',\n    data: JSON.stringify({ scriptFile, route: '/dynamicForm' }),\n  });\n};\n\n// #region 给 webview 调用的\nexport { getDynamicForm } from '@share/uTools/webviewBaseController';\n\nexport const askChatGPTForDynamicFormPage = (\n  data: AskChatGPTForDynamicFormPageWebviewData,\n) => {\n  return baseAskChatGPTForDynamicFormPage({\n    ...data,\n    validateJsonSchemaTypeName: 'PageConfig',\n  });\n};\n\nexport const runDynamicFormScript: MethodHandle = (data) => {\n  if (controller[data.method]) {\n    return controller[data.method](data);\n  }\n  return Promise.reject(`方法不存在：${data.method}`);\n};\n\n// #endregion\n"
  },
  {
    "path": "uTools/动态表单 demo/src/api.ts.ejs",
    "content": "import { request } from \"@/utils/request\";\n<% if (locals.api) { %>\n// #region <%= api.title %>\n<%= type %>\n\n<% if (api.req_query.length > 0 || api.req_params.length > 0 || api.query_path.params.length > 0) { _%>\nexport interface I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Params {\n\t<% api.req_query.filter(query => query.name !== pagination.page && query.name !== pagination.size).map(query => { _%>\n\t\t<%= query.name %>?: string;\n\t<% }) _%>\n\t<% api.req_params.filter(s => s.name !== pagination.page && s.name !== pagination.size).map(query => { _%>\n\t\t<%= query.name %>?: string;\n\t<% }) _%>\n\t<% api.query_path.params.filter(s => s.name !== pagination.page && s.name !== pagination.size).map(query => { _%>\n\t\t<%= query.name %>?: string;\n\t<% }) _%>\n\t<% if (pagination.show) { _%>\n\t\t<%= pagination.page %>: number;\n\t\t<%= pagination.size %>: number;\n\t<% } _%>\n}\n<% } %> \n<% if (requestBodyType && api.req_body_other.indexOf('{}') < 0) { %>\n    <%= requestBodyType %> \n<% } %> \n\n/**\n* <%= api.title %> \n* /project/<%= api.project_id %>/interface/api/<%= api._id %> \n* @author <%= api.username %>  \n* \n<% if (api.req_query.length > 0 || api.req_params.length > 0 || api.query_path.params.length > 0) { -%>* @param {I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Params} params<%- \"\\n\" %><% } _%>\n<% if (requestBodyType && api.req_body_other.indexOf('{}')<0) { -%>* @param {I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Data} data<%- \"\\n\" %><% } _%>\n* @returns\n*/\nexport function <%= funcName %> (\n<% if (api.req_query.length>0 || api.req_params.length > 0 || api.query_path.params.length > 0) { %>\nparams: I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Params,\n<% } _%>\n<% if (requestBodyType) { %> \ndata: I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Data\n<% } %> \n) {\nreturn request<<%= typeName %>>({\n\t  url: `http://127.0.0.1:3000<%= api.query_path.path.replace(/\\{/g,\"${params.\") %>`, \n\t\tmethod: '<%= api.method %>',\n\t\t<% if(api.req_query.length>0 || api.req_params.length > 0) { %>params,<% } _%>\n        <% if (requestBodyType && api.req_body_other.indexOf('{}')<0) {%>data,<% } %> \n\t})\n}\n// #endregion\n<% } else { %>\n// #region\nexport interface I<%= fetchName.slice(0, 1).toUpperCase() + fetchName.slice(1) %>Result {\n  code: number;\n\tmsg: string;\n\t<% if (!pagination.show) { _%>\n\tresult: {\n\t\t<% columns.map((item, index) => { _%>\n\t\t\t<%= item.key || `column${index+1}` %>: string;\n\t\t<% }) _%>\n\t\t}[];\n\t<% } else { _%>\n\t\tresult: {\n\t\t\trecords: {\n\t\t\t\t<% columns.map((item, index) => { _%>\n\t\t\t\t\t<%= item.key || `column${index+1}` %>: string;\n\t\t\t\t<% }) _%>\n\t\t\t}[];\n\t\t\ttotal: number;\n\t\t}\n\t<% } _%>\n}\n\nexport interface I<%= fetchName.slice(0, 1).toUpperCase() + fetchName.slice(1) %>Params {\n\t<% filters.map(item => { _%>\n\t\t<% if(item.component !== \"range-picker\") { _%>\n\t\t\t <%= item.key %>?: string;\n\t\t<% } else { _%>\n\t\t\t<%= item.key %>Start?: string;\n\t\t\t<%= item.key %>End?: string;\n\t\t<% } _%>\n\t<% }) _%>\n\t<% if (pagination.show) { _%>\n\t\t<%= pagination.page %>: number;\n\t\t<%= pagination.size %>: number;\n\t<% } _%>\n}\n\nexport function <%= fetchName %>(\nparams: I<%= fetchName.slice(0, 1).toUpperCase() + fetchName.slice(1) %>Params\n) {\nreturn request<I<%= fetchName.slice(0, 1).toUpperCase() + fetchName.slice(1) %>Result>({\n\turl: `http://127.0.0.1:3000<%= createBlockPath %>/<%= fetchName %>`, \n\tmethod: \"GET\",\n\tparams,\n});\n}\n// #endregion\n<% } %>"
  },
  {
    "path": "uTools/动态表单 demo/src/index.vue.ejs",
    "content": "<template>\n  <a-row class=\"filterForm\" :gutter=\"30\">\n    <% filters.map(item => { _%> \n\t\t  <a-col :xs=\"24\" :sm=\"24\" :md=\"12\" :lg=\"12\" :xl=\"8\" :xxl=\"6\">\n\t\t\t\t<% if(item.component === \"select\") { %>\n\t\t\t\t<a-form-item label=\"<%= item.label %>\">\n\t\t\t\t\t<a-select\n\t\t\t\t\t\tv-model:value=\"model.filterForm.<%= item.key %>\"\n\t\t\t\t\t\t:options=\"model.options.<%= item.key %>\"\n\t\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\t\tshow-search\n\t\t\t\t\t\tallow-clear\n\t\t\t\t\t\t<% if(item.remoteFetch) { _%>\n\t\t\t\t\t\t:filter-option=\"false\"\n\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t\toption-filter-prop=\"label\"\n\t\t\t\t\t\t@change=\"presenter.handleSearch\"\n\t\t\t\t\t\t<% if(item.remoteFetch) { _%>\n\t\t\t\t\t\t@search=\"presenter.handleSearch<%= item.key.slice(0, 1).toUpperCase() + item.key.slice(1) %>\"\n\t\t\t\t\t\t<% } _%>\n\t\t\t\t\t></a-select>\n\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%> \n\t\t\t\t<% if(item.component === \"input\") { _%>\n\t\t\t\t<a-form-item label=\"<%= item.label %>\">\n\t\t\t\t\t<a-input\n\t\t\t\t\t\tv-model:value=\"model.filterForm.<%= item.key %>\"\n\t\t\t\t\t\tplaceholder=\"<%= item.placeholder %>\"\n\t\t\t\t\t\tallow-clear\n\t\t\t\t\t\t@press-enter=\"presenter.handleSearch\"\n\t\t\t\t\t></a-input>\n\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%> \n\t\t\t\t<% if(item.component === \"range-picker\") { _%>\n\t\t\t\t<a-form-item label=\"<%= item.label %>\">\n\t\t\t\t\t<a-range-picker\n\t\t\t\t\t\tv-model:value=\"model.filterForm.<%= item.key %>\"\n\t\t\t\t\t\t:placeholder=\"['开始时间', '结束时间']\"\n\t\t\t\t\t\tformat=\"YYYY-MM-DD\"\n\t\t\t\t\t\tvalueFormat=\"YYYY-MM-DD\"\n\t\t\t\t\t\t@change=\"presenter.handleSearch\"\n\t\t\t\t\t/>\n\t\t\t\t</a-form-item>\n\t\t\t\t<% } _%> \n\t\t\t</a-col>\n\t\t<% }) _%>\n\t\t<a-col style=\"text-align: right; flex: 1\">\n\t\t\t<a-space>\n\t\t\t\t<a-button @click=\"presenter.handleClear\">重置</a-button>\n        <a-button @click=\"presenter.handleSearch\" type=\"primary\">查询</a-button>\n        <a-button @click=\"presenter.handleCreate\" type=\"primary\">\n          <template #icon><PlusOutlined /></template>\n          新增\n        </a-button>\n\t\t\t</a-space>\n\t\t</a-col>\n  </a-row>\n  <a-table\n    :loading=\"model.loading.list\"\n    :columns=\"columns\"\n    :data-source=\"model.tableList.value\"\n    :pagination=\"false\"\n  >\n\t\t<template #bodyCell=\"{ column, record }\">\n\t\t\t<% columns.filter(item => item.slot).map((item, index) => { _%>\n\t\t\t\t<template v-if=\"column.key === '<%= item.key %>'\">\n\t\t\t\t\t{{ record.<%= item.key %> }}\n\t\t\t\t</template>\n\t\t\t<% }) _%>\n\t\t\t<template v-if=\"column.key === 'operation'\">\n\t\t\t\t<a-space :size=\"0\">\n\t\t\t\t\t<% if(includeModifyModal) { _%>\n\t\t\t\t\t<a-button\n\t\t\t\t\t\ttype=\"link\"\n\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t@click=\"\n\t\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\t\tpresenter.handleView(record);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\"\n\t\t\t\t\t>\n\t\t\t\t\t\t查看\n\t\t\t\t\t</a-button>\n\t\t\t\t\t<% } _%>\n\t\t\t\t\t<a-button\n\t\t\t\t\t\ttype=\"link\"\n\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t@click=\"\n\t\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\t\tpresenter.handleEdit(record);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\"\n\t\t\t\t\t>\n\t\t\t\t\t\t编辑\n\t\t\t\t\t</a-button>\n\t\t\t\t\t<a-button\n\t\t\t\t\t\ttype=\"link\"\n\t\t\t\t\t\tdanger\n\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t@click=\"\n\t\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\t\tpresenter.handleDel(record);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\"\n\t\t\t\t\t>\n\t\t\t\t\t\t删除\n\t\t\t\t\t</a-button>\n\t\t\t\t</a-space>\n\t\t\t</template>\n\t\t</template>\n  </a-table>\n  <% if(pagination.show) { _%>\n  <a-pagination\n    style=\"margin-top: 10px\"\n    @change=\"presenter.handlePageChange\"\n\t@showSizeChange=\"presenter.handlePageChange\"\n    v-model:current=\"model.pagination.page\"\n    :total=\"model.pagination.total\"\n    show-size-changer\n    show-quick-jumper\n\t:show-total=\"(total: number) => `共 ${total} 条`\"\n  ></a-pagination>\n  <% } _%> <% if(includeModifyModal) { _%>\n  <ModifyModal\n    :id=\"model.modalInfo.id\"\n    :title=\"model.modalInfo.title\"\n    :visible=\"model.modalInfo.visible\"\n    :action=\"model.modalInfo.action\"\n    @ok=\"presenter.handleModalOk\"\n    @cancel=\"presenter.handleModalCancel\"\n  ></ModifyModal>\n  <% } _%>\n</template>\n<script lang=\"ts\" setup>\n  import { PlusOutlined } from \"@ant-design/icons-vue\";\n  <% if(includeModifyModal) { _%>\n  import ModifyModal from \"./ModifyModal/index.vue\";\n  <% } _%>\n  import { usePresenter } from \"./presenter\";\n\n  const presenter = usePresenter();\n  const { model } = presenter;\n\n  const columns = [\n    <% columns.map((item, index) => { _%>\n  \t\t{\n        title: \"<%= item.title || `column${index+1}` %>\",\n  \t\t\tdataIndex: \"<%= item.dataIndex || `column${index+1}` %>\",\n  \t\t\tkey: \"<%= item.key || `column${index+1}` %>\",\n  \t\t\t<% if(item.width) {%>width: \"<%= item.width %>\",<% } _%>\n  \t\t},\n  \t<% }) _%>\n  \t{\n      title: \"操作\",\n      key: \"operation\",\n  \t\twidth: 100\n    }\n  ];\n</script>\n"
  },
  {
    "path": "uTools/动态表单 demo/src/model.ts.ejs",
    "content": "import { reactive, ref } from \"vue\";\n<% if(locals.api){ %>\nimport { I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Result } from \"./api\";\n<% } else { %>\nimport { I<%= fetchName.slice(0, 1).toUpperCase() + fetchName.slice(1) %>Result } from \"./api\";\n<% } %>\n<% if(!locals.api){ %>\ninterface ITableListItem {\n\t<% columns.map((item, index) => { _%>\n\t\t/** <%= item.title %> */\n\t\t<%= item.key || `column${index+1}` %>: string;\n\t<% }) _%>\n\t/**\n   * 接口返回的数据，新增字段不需要改 ITableListItem 直接从这里取\n   */\n\tapiResult: I<%= fetchName.slice(0, 1).toUpperCase() + fetchName.slice(1) %>Result<%- result %>[0]\n}\n<% } %>\ninterface IFormData {\n\t<% filters.map(item => { _%>\n\t\t/** <%= item.label %> */\n\t\t<% if(item.component === \"range-picker\") { _%>\n\t\t\t<%= item.key %>?: [string,string];\n\t\t<% } _%>\n\t\t<% if(item.component !== \"range-picker\") { _%>\n\t\t\t<%= item.key %>?: string;\n\t\t<% } _%>\n\t<% }) _%>\n}\n<% if(filters.some(s => s.component === \"select\" )){ %>\ninterface IOptionItem {\n  label: string;\n  value: string;\n}\n\ninterface IOptions {\n  <% filters.filter(s => s.component === \"select\").map(item => { _%>\n\t<%= item.key %>: IOptionItem[],\n  <% }) _%>\n}\n\nconst defaultOptions: IOptions = {\n\t<% filters.filter(s => s.component === \"select\").map(item => { _%>\n\t\t<%= item.key %>: [],\n\t<% }) _%>\n};\n<% } %>\nexport const defaultFormData: IFormData = {\n\t<% filters.map(item => { _%>\n\t\t<%= item.key %>: undefined,\n\t<% }) _%>\n};\n\nexport const useModel = () => {\n  const filterForm = reactive<IFormData>({ ...defaultFormData });\n\t<% if(filters.some(s => s.component === \"select\" )){ %>\n  \t\tconst options = reactive<IOptions>({ ...defaultOptions });\n\t<% } %>\n\t<% if(locals.api){ _%>\n\t\tconst tableList = ref<(I<%= funcName.slice(0, 1).toUpperCase() + funcName.slice(1) %>Result<%- result %>[0] & { _?: unknown })[]>(\n\t\t\t[],\n\t\t);\n\t<% } else { _%>\n\t\tconst tableList = ref<(ITableListItem & { _?: unknown })[]>(\n\t\t\t[],\n\t\t);\n\t<% } _%>\n\t<% if(pagination.show) { %>\n\t\tconst pagination = reactive<{\n\t\t\tpage: number;\n\t\t\tpageSize: number;\n\t\t\ttotal: number;\n\t\t}>({\n\t\t\tpage: 1,\n\t\t\tpageSize: 10,\n\t\t\ttotal: 0,\n\t\t});\n\t<% } %>\n  const loading = reactive<{ list: boolean }>({\n    list: false,\n  });\n  <% if(includeModifyModal) { %>\n\tconst modalInfo = reactive<{\n\t\tvisible: boolean;\n\t\ttitle: string;\n\t\tid?: number;\n\t\taction: \"add\" | \"edit\" | \"view\";\n\t}>({\n\t\tvisible: false,\n\t\ttitle: \"\",\n\t\taction: \"add\",\n\t});\n  <% } %>\n  return {\n    filterForm,\n\t\t<% if(filters.some(s => s.component === \"select\" )){ _%>\n    options,\n\t\t<% } _%>\n    tableList,\n\t\t<% if(pagination.show) { _%>\n\t\tpagination,\n\t\t<% } _%>\n\t\t\tloading,\n\t\t<% if(includeModifyModal) { _%>\n\t\tmodalInfo,\n\t\t<% } _%>\n  };\n};\n\nexport type Model = ReturnType<typeof useModel>;\n"
  },
  {
    "path": "uTools/动态表单 demo/src/presenter.ts.ejs",
    "content": "import Service from \"./service\";\nimport { defaultFormData, useModel } from \"./model\";\nimport { createVNode, onMounted } from \"vue\";\nimport { message, Modal } from \"ant-design-vue\";\nimport { ExclamationCircleOutlined } from \"@ant-design/icons-vue\";\n<% if(filters.some(item => item.component === \"select\" && item.remoteFetch)) { _%>\nimport { useDebounceFn } from \"@vueuse/core\";\n<% } _%>\n\nexport const usePresenter = () => {\n  const model = useModel();\n  const service = new Service(model);\n\n  onMounted(() => {\n    service.<%= serviceName %>();\n  });\n\n  const handleClear = () => {\n\t\tObject.assign(model.filterForm, defaultFormData)\n\t\t<% if(pagination.show) { _%>\n\t\t\tmodel.pagination.page = 1;\n\t\t<% } _%>\n    service.<%= serviceName %>();\n  };\n\n  const handleSearch = () => {\n\t\t<% if(pagination.show) { _%>\n\t\t\tmodel.pagination.page = 1;\n\t\t<% } _%>\n    service.<%= serviceName %>();\n  };\n\n  <% if(pagination.show) { _%>\n  const handlePageChange = (page: number, pageSize: number) => {\n    if (pageSize !== model.pagination.pageSize) {\n      model.pagination.pageSize = pageSize;\n      model.pagination.page = 1;\n    } else {\n      model.pagination.page = page;\n    }\n    service.<%= serviceName %>();\n  };\n  <% } _%>\n\n\t<% filters.filter(item => item.component === \"select\" && item.remoteFetch).map(item => { _%> \n\tconst handleSearch<%= item.key.slice(0, 1).toUpperCase() + item.key.slice(1) %> = useDebounceFn((value: string) => {\n    if (!value) {\n      return;\n    }\n    service.search<%= item.key.slice(0, 1).toUpperCase() + item.key.slice(1) %>(value);\n  }, 400);\n\t\n\t<% }) _%>\n\n  const handleDel = (record: typeof model.tableList.value[0]) => {\n    Modal.confirm({\n      title: \"此操作将删除该选项，是否继续？\",\n      icon: createVNode(ExclamationCircleOutlined),\n\t\t\tokText: \"确定\",\n      cancelText: \"取消\",\n      onOk() {\n        message.success(\"删除成功\");\n      },\n    });\n  };\n\n  const handleCreate = () => {\n\t<% if(includeModifyModal) { _%>\n    model.modalInfo.visible = true;\n    model.modalInfo.title = \"新建\";\n    model.modalInfo.action = \"add\";\n    model.modalInfo.id = undefined;\n\t<% } _%>\n  };\n\n  const handleEdit = (record: typeof model.tableList.value[0]) => {\n\t<% if(includeModifyModal) { _%>\n    model.modalInfo.visible = true;\n    model.modalInfo.title = \"编辑\";\n    model.modalInfo.action = \"edit\";\n    model.modalInfo.id = record.id;\n\t<% } _%>\n  };\n\n  <% if(includeModifyModal) { _%>\n  const handleView = (record: typeof model.tableList.value[0]) => {\n    model.modalInfo.visible = true;\n    model.modalInfo.title = \"查看\";\n    model.modalInfo.action = \"view\";\n    model.modalInfo.id = record.id;\n  };\n\n  const handleModalOk = () => {\n    model.modalInfo.visible = false;\n    service.<%= serviceName %>();\n  };\n\n  const handleModalCancel = () => {\n    model.modalInfo.visible = false;\n  };\n  <% } _%>\n\n  return {\n    model,\n    service,\n    handleClear,\n    handleSearch,\n\t\t<% if(pagination.show) { _%>\n\t\thandlePageChange,\n    <% } _%>\n\t\t<% filters.filter(item => item.component === \"select\" && item.remoteFetch).map(item => { _%> \n\t\t\thandleSearch<%= item.key.slice(0, 1).toUpperCase() + item.key.slice(1) %>,\n\t\t<% }) _%>\n\thandleDel,\n\thandleCreate,\n    handleEdit,\n\t<% if(includeModifyModal) { _%>\n\thandleView,\n\thandleModalOk,\n\thandleModalCancel\n\t<% } _%>\n  };\n};\n"
  },
  {
    "path": "uTools/动态表单 demo/src/service.ts.ejs",
    "content": "import { <%= locals.api ? funcName : fetchName %> } from \"./api\";\nimport { Model } from \"./model\"; \n\nexport default class Service {\n  private model: Model;\n\n  constructor(model: Model) {\n    this.model = model;\n  }\n\n  async <%= serviceName %>() {\n    this.model.loading.list = true;\n\t\t<% filters.map(item => { _%>\n\t\t\t<% if(item.component === \"range-picker\") { _%>\n\t\t\t\tlet <%= item.key %>Start: string | undefined = undefined;\n\t\t\t\tlet <%= item.key %>End: string | undefined = undefined;\n\t\t\t\tif (\n\t\t\t\tthis.model.filterForm.<%= item.key %> &&\n\t\t\t\tthis.model.filterForm.<%= item.key %>[0]\n\t\t\t\t) {\n\t\t\t\t\t<%= item.key %>Start = `${this.model.filterForm.<%= item.key %>[0]} 00:00:00`;\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\tthis.model.filterForm.<%= item.key %> &&\n\t\t\t\tthis.model.filterForm.<%= item.key %>[1]\n\t\t\t\t) {\n\t\t\t\t\t<%= item.key %>End = `${this.model.filterForm.<%= item.key %>[1]} 23:59:59`;\n\t\t\t\t}\n\t\t\t<% } _%>\n\t\t<% }) _%>\n    const res = await <%= locals.api ? funcName : fetchName %>({\n\t\t\t<% filters.map(item => { _%>\n\t\t\t\t<% if(item.component !== \"range-picker\") { _%>\n\t\t\t\t\t<%= item.key %>: this.model.filterForm.<%= item.key %>,\n\t\t\t\t<% } else { _%>\n\t\t\t\t\t<%= item.key %>Start: <%= item.key %>Start,\n\t\t\t\t\t<%= item.key %>End: <%= item.key %>End,\n\t\t\t\t<% } _%>\n\t\t\t<% }) _%>\n\t\t\t<% if(pagination.show) { _%>\n\t\t\t\t<%= pagination.page %>: this.model.pagination.page,\n\t\t\t\t<%= pagination.size %>: this.model.pagination.pageSize,\n\t\t\t<% } _%>\n\t\t}).finally(() => {\n\t\t\tthis.model.loading.list = false;\n\t\t});\n    this.model.tableList.value = res<%- result %>.map((s) => {\n      return {\n\t\t...s,\n\t\t<% columns.map((item, index) => { _%>\n\t\t\t<%= item.key || `column${index+1}` %>: s.<%= item.key || `column${index+1}` %>,\n\t\t<% }) _%>\n\t\tapiResult: s\n      };\n    });\n\t<% if(pagination.show) { _%>\n\tthis.model.pagination.total = res.<%- pagination.total %>;\n\t<% } _%>\n  }\n\n\t<% filters.filter(item => item.component === \"select\" && item.remoteFetch).map(item => { _%> \n\t\tasync search<%= item.key.slice(0, 1).toUpperCase() + item.key.slice(1) %>(value: string) {\n\t\t\tconst res = await Promise.resolve([{ label: \"1\", value: \"1\" }]);\n\t\t\tthis.model.options.<%= item.key %> = res;\n\t\t}\n\t\t\n\t<% }) _%>\n}\n"
  },
  {
    "path": "uTools/动态表单 demo/src/temp.mock.script",
    "content": ".get(`<%= createBlockPath %>/<%= fetchName %>`, async (ctx, next) => { <%- mockCode %> ctx.body = <%- mockData %>\n})\n"
  },
  {
    "path": "uTools/动态表单 demo/src/temp.mock.type.ejs",
    "content": "{\n  code: number;\n\tmsg: string;\n\t<% if (!pagination.show) { _%>\n\tresult: {\n\t\t<% columns.map((item, index) => { _%>\n\t\t\t<%= item.key || `column${index+1}` %>: string;\n\t\t<% }) _%>\n\t}[];\n\t<% } else { _%>\n\t\tresult: {\n\t\t\trecords: {\n\t\t\t\t<% columns.map((item, index) => { _%>\n\t\t\t\t\t<%= item.key || `column${index+1}` %>: string;\n\t\t\t\t<% }) _%>\n\t\t\t}[];\n\t\t\ttotal: number;\n\t\t}\n\t<% } _%>\n}"
  },
  {
    "path": "uTools/截屏并转base64/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/截屏并转base64/script/src/main.ts",
    "content": "import { clipboard } from 'electron';\nimport { screenCapture } from '@share/utils/uTools';\n\nexport const bootstrap = async () => {\n  const base64 = await screenCapture();\n  clipboard.writeText(base64);\n  utools.outPlugin();\n  utools.hideMainWindow();\n};\n"
  },
  {
    "path": "uTools/根据 DevOps 需求标题创建 GIT commit - 截图/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/根据 DevOps 需求标题创建 GIT commit - 截图/script/src/main.ts",
    "content": "import { ocr } from '@share/utils/uTools';\nimport { clipboard } from 'electron';\n\nexport const bootstrap = async (scriptFile?: string) => {\n  const availableFormats = clipboard.availableFormats('clipboard');\n  if (!availableFormats.some((s) => s.includes('image'))) {\n    return '剪贴板里没有截图';\n  }\n  const base64 = clipboard.readImage('clipboard').toDataURL();\n  const ocrRes = await ocr({ base64, model: 'ocr_system' });\n  if (ocrRes.result?.texts && ocrRes.result.texts.length > 1) {\n    const task = ocrRes.result.texts[0].trim();\n    const title = ocrRes.result.texts[1].trimStart();\n    utools.outPlugin();\n    utools.hideMainWindowPasteText(`feat(T${task}): #${task}/${title}`);\n  } else {\n    const result = ocrRes.result?.texts?.[0]?.trimStart() || '';\n    const match = result.match(/^(\\d+)(.*)/);\n    if (match) {\n      const task = match[1]; // 开头的数字部分\n      const title = match[2]; // 其余的内容\n      utools.outPlugin();\n      utools.hideMainWindowPasteText(`feat(T${task}): #${task}/${title}`);\n    } else {\n      return result;\n    }\n  }\n};\n"
  },
  {
    "path": "uTools/根据 DevOps 需求标题创建 GIT 分支名 - 截图/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/根据 DevOps 需求标题创建 GIT 分支名 - 截图/script/src/main.ts",
    "content": "/* eslint-disable prefer-destructuring */\nimport { LLMMessage } from '@share/uTools/webviewBaseController';\nimport { askChatGPT as askOpenai, ocr } from '@share/utils/uTools';\nimport { clipboard } from 'electron';\n\nexport const bootstrap = async (scriptFile?: string) => {\n  const availableFormats = clipboard.availableFormats('clipboard');\n  if (!availableFormats.some((s) => s.includes('image'))) {\n    return '剪贴板里没有截图';\n  }\n  const base64 = clipboard.readImage('clipboard').toDataURL();\n  const ocrRes = await ocr({ base64, model: 'ocr_system' });\n  let task = '';\n  let title = '';\n  if (ocrRes.result?.texts && ocrRes.result.texts.length > 1) {\n    task = ocrRes.result.texts[0].trim();\n    title = ocrRes.result.texts[1].trimStart();\n  } else {\n    const result = ocrRes.result?.texts?.[0]?.trimStart() || '';\n    const match = result.match(/^(\\d+)(.*)/);\n    if (match) {\n      task = match[1]; // 开头的数字部分\n      title = match[2]; // 其余的内容\n    }\n  }\n  if (title) {\n    const requestPrompt = `\n下面是一个需求的简要索说明，需要根据这个说明创建 git 分支，请给出英文分支名，不要直接翻译，要自然、流畅和地道，不要加 feature、feat 等分支特性，用户自己处理\n\n\\`\\`\\`\n${title}\n\\`\\`\\`\n`;\n    // const content = await askOpenai({\n    //   messages: [{ role: 'user', content: requestPrompt }],\n    //   handleChunk: () => {},\n    // });\n    // return `feat/T${task}_${content.content}`;\n\n    utools.redirect(['lowcode', 'lowcode'], {\n      type: 'text',\n      data: JSON.stringify({\n        scriptFile,\n        route: '/chat',\n        content: requestPrompt,\n        form: {\n          task,\n        },\n      }),\n    });\n    return;\n  }\n  return JSON.stringify(ocrRes);\n};\n\n// 给页面调用的\nexport const askChatGPT = async (data: {\n  messages: LLMMessage;\n  handleChunk: (chunck: string) => void;\n  model: {\n    task: string;\n  };\n}) => {\n  const res = await askOpenai({ ...data, model: undefined });\n  data.handleChunk(`\n\t\n完整分支名：\n\\`\\`\\`\nfeat/T${data.model.task}_${res.content.replace(/```/g, '').replace(/`/g, '')}\n\\`\\`\\`\t\t\n`);\n  return res;\n};\n"
  },
  {
    "path": "uTools/根据 DevOps 需求标题创建 GIT 分支名 - 截图 - TypeCheck/config/schema.ts",
    "content": "export type TaskInfo = {\n  // 需求 id，用户发送内容的开头数字部分\n  taskId: string;\n  // 需求标题，用户发送内容去掉开头数字部分，请翻译成英文，不要直接翻译，要自然、流畅和地道，这部分内容会作为 git 分支名，请用中划线代替翻译后的空格\n  taskTitle: string;\n};\n"
  },
  {
    "path": "uTools/根据 DevOps 需求标题创建 GIT 分支名 - 截图 - TypeCheck/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/根据 DevOps 需求标题创建 GIT 分支名 - 截图 - TypeCheck/script/src/main.ts",
    "content": "/* eslint-disable prefer-destructuring */\nimport { validate } from '@share/TypeChatSlim/utools';\nimport { LLMMessage } from '@share/uTools/webviewBaseController';\nimport {\n  askChatGPT as askOpenai,\n  getBlockJsonValidSchema,\n  ocr,\n} from '@share/utils/uTools';\nimport { clipboard } from 'electron';\n\nexport const bootstrap = async (scriptFile?: string) => {\n  const availableFormats = clipboard.availableFormats('clipboard');\n  if (!availableFormats.some((s) => s.includes('image'))) {\n    return '剪贴板里没有截图';\n  }\n  const base64 = clipboard.readImage('clipboard').toDataURL();\n  const ocrRes = await ocr({ base64, model: 'ocr_system' });\n  const schema = getBlockJsonValidSchema(scriptFile!);\n  const text = ocrRes.result?.texts?.join(' ') || '';\n  const typeName = 'TaskInfo';\n  const requestPrompt = `\nYou are a service that translates user requests into JSON objects of type \"${typeName}\" according to the following TypeScript definitions:\n\\`\\`\\`ts\n${schema}\n\\`\\`\\`\nThe following is a user request:\n\\`\\`\\`\n${text}\n\\`\\`\\`\nThe following is the user request translated into a JSON object with 2 spaces of indentation and no properties with the value undefined:\n`;\n  utools.redirect(['lowcode', 'lowcode'], {\n    type: 'text',\n    data: JSON.stringify({\n      scriptFile,\n      route: '/chat',\n      content: requestPrompt,\n    }),\n  });\n};\n\n// 给页面调用的\nexport const askChatGPT = async (data: {\n  messages: LLMMessage;\n  handleChunk: (chunck: string) => void;\n  scriptFile: string;\n}) => {\n  const schema = getBlockJsonValidSchema(data.scriptFile);\n  const typeName = 'TaskInfo';\n  const content = await askOpenai({\n    messages: data.messages,\n    handleChunk: data.handleChunk,\n  });\n  const valid = validate<{ taskId: string; taskTitle: string }>(\n    content.content,\n    schema,\n    typeName,\n  );\n  if (valid.success) {\n    data.handleChunk(`\n\n完整分支名：\n\\`\\`\\`\nfeat/T${valid.data.taskId}_${valid.data.taskTitle\n      .replace(/```/g, '')\n      .replace(/`/g, '')}\n\\`\\`\\`\n`);\n  } else {\n    data.handleChunk(`\n\n> JSON 校验不通过\n\n${valid.message}\n`);\n  }\n  return content;\n};\n"
  },
  {
    "path": "uTools/根据当前分支名称创建 GIT commit/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/根据当前分支名称创建 GIT commit/script/src/main.ts",
    "content": "import { clipboard } from 'electron';\nimport * as execa from 'execa';\nimport { getShareData } from '@share/utils/shareData';\n\nexport const bootstrap = (scriptFile?: string) => {\n  const { activeWindow } = getShareData();\n  try {\n    const projectPath =\n      utools.isWindows() && activeWindow?.startsWith('/')\n        ? activeWindow.substring(1)\n        : activeWindow;\n    const res = execa.sync('git', [\n      '-C',\n      projectPath || '.',\n      'rev-parse',\n      '--abbrev-ref',\n      'HEAD',\n    ]);\n    if (res.stdout) {\n      const match = res.stdout.match(/T(\\d+)_/);\n      if (match && match[1]) {\n        utools.outPlugin();\n        utools.hideMainWindowPasteText(`feat(T${match[1]}): #${match[1]}/`);\n        return res.stdout;\n      }\n      utools.outPlugin();\n      utools.hideMainWindowPasteText(res.stdout);\n      return;\n    }\n    return JSON.stringify(res);\n  } catch (ex) {\n    return (ex as object).toString();\n  }\n};\n"
  },
  {
    "path": "uTools/翻译为驼峰格式-首字母大写/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/翻译为驼峰格式-首字母大写/script/src/main.ts",
    "content": "import { clipboard } from 'electron';\nimport { createChatCompletion } from '@share/LLM/openaiV2';\n\nexport const bootstrap = async () => {\n  const text = clipboard.readText();\n  if (!text) {\n    utools.showNotification('请先复制内容');\n    return;\n  }\n  let res = await createChatCompletion({\n    messages: [\n      {\n        role: 'system',\n        content: `你是一个翻译家，你的目标是把中文翻译成英文单词，请翻译时使用驼峰格式，小写字母开头，不要带翻译腔，而是要翻译得自然、流畅和地道，使用优美和高雅的表达方式。请翻译下面用户输入的内容`,\n      },\n      {\n        role: 'user',\n        content: text,\n      },\n    ],\n  });\n  res = res.charAt(0).toUpperCase() + res.slice(1);\n  utools.outPlugin();\n  utools.hideMainWindowPasteText(res);\n};\n"
  },
  {
    "path": "uTools/翻译为驼峰格式-首字母小写/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/翻译为驼峰格式-首字母小写/script/src/main.ts",
    "content": "import { clipboard } from 'electron';\nimport { createChatCompletion } from '@share/LLM/openaiV2';\n\nexport const bootstrap = async () => {\n  const text = clipboard.readText();\n  if (!text) {\n    utools.showNotification('请先复制内容');\n    return;\n  }\n  let res = await createChatCompletion({\n    messages: [\n      {\n        role: 'system',\n        content: `你是一个翻译家，你的目标是把中文翻译成英文单词，请翻译时使用驼峰格式，小写字母开头，不要带翻译腔，而是要翻译得自然、流畅和地道，使用优美和高雅的表达方式。请翻译下面用户输入的内容`,\n      },\n      {\n        role: 'user',\n        content: text,\n      },\n    ],\n  });\n  res = res.charAt(0).toLowerCase() + res.slice(1);\n  utools.outPlugin();\n  utools.hideMainWindowPasteText(res);\n};\n"
  },
  {
    "path": "uTools/英文翻译中文/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/英文翻译中文/script/src/main.ts",
    "content": "import { clipboard } from 'electron';\nimport { createChatCompletion } from '@share/LLM/openaiV2';\n\nexport const bootstrap = async () => {\n  const text = clipboard.readText();\n  if (!text) {\n    utools.showNotification('请先复制内容');\n    return;\n  }\n  const res = await createChatCompletion({\n    messages: [\n      {\n        role: 'system',\n        content: `你是一个翻译家，你的目标是把英文翻译成中文，请翻译时不要带翻译腔，而是要翻译得自然、流畅和地道，使用优美和高雅的表达方式。请翻译下面用户输入的内容`,\n      },\n      {\n        role: 'user',\n        content: text,\n      },\n    ],\n  });\n  return res;\n};\n"
  },
  {
    "path": "uTools/英文：中文格式的描述转 TS 类型/README.md",
    "content": "customerName：甲方姓名\ncustomerMobile：甲方手机号\nreceiverMobile：报价单手机号\nidCard：证件号码\nidCardType：证件类型\nhouseAddress：房屋地址\norderCode：报价单号\ndesignArea：设计面积（可修改）\nproductType：产品类型\ntotalAmount：总报价款\ndesignPrice：设计单价（可修改）\n"
  },
  {
    "path": "uTools/英文：中文格式的描述转 TS 类型/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/英文：中文格式的描述转 TS 类型/script/src/main.ts",
    "content": "import { clipboard } from 'electron';\nimport { askChatGPT as askOpenai } from '@share/utils/uTools';\nimport { AskChatGPT } from '@share/uTools/webviewBaseController';\n\nexport const bootstrap = async (scriptFile?: string) => {\n  const clipboardText =\n    (clipboard.readText() || '').trim() ||\n    '客户验收状态:1.无需验收、2.待验收、3已验收';\n  const requestPrompt =\n    `You are a service that translates user requests into TypeScript Interface， use value as a comment in JSDoc format:\\n` +\n    `The following is a user request:\\n` +\n    `\"\"\"\\n${clipboardText}\\n\"\"\"\\n`;\n  utools.redirect(['lowcode', 'lowcode'], {\n    type: 'text',\n    data: JSON.stringify({\n      scriptFile,\n      route: '/chat',\n      content: requestPrompt,\n    }),\n  });\n};\n\n// 给页面调用的\nexport const askChatGPT: AskChatGPT = (data) =>\n  askOpenai({ ...data, model: undefined });\n"
  },
  {
    "path": "uTools/获取命令行命令/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/获取命令行命令/script/src/main.ts",
    "content": "import { createChatCompletion } from '@share/LLM/openaiV2';\nimport { clipboard } from 'electron';\n\nexport const bootstrap = async (scriptFile?: string) => {\n  const text = clipboard.readText();\n  let platform = utools.isWindows() ? 'windows' : 'mac';\n  if (utools.isLinux()) {\n    platform = 'linux';\n  }\n  if (!text) {\n    utools.showNotification('请先复制内容');\n    return;\n  }\n  let res = await createChatCompletion({\n    messages: [\n      // {\n      //   role: 'system',\n      //   content: `你精通各种 OS 平台命令行，你的目标是根据用户的要求，帮助用户获取命令行命令，直接给出可执行的命令，用户复制后可直接执行。下面用户输入的内容：`,\n      // },\n      {\n        role: 'user',\n        content: `${platform} 平台下， ${text}，返回可执行的命令即可，不要带多余的信息`,\n      },\n    ],\n  });\n  res = res.replace(/`/g, '');\n  utools.outPlugin();\n  utools.hideMainWindowPasteText(res);\n};\n"
  },
  {
    "path": "uTools/设置配置信息/script/index.ts",
    "content": "import { bootstrap } from './src/main';\n\nconst res = bootstrap();\n// @ts-ignore\nreturn res;\n"
  },
  {
    "path": "uTools/设置配置信息/script/src/main.ts",
    "content": "/* eslint-disable no-template-curly-in-string */\nimport { getShareData, saveShareData as save } from '@share/utils/shareData';\n\nexport const bootstrap = async (scriptFile?: string) => {\n  utools.redirect(['lowcode', 'lowcode'], {\n    type: 'text',\n    data: JSON.stringify({ scriptFile, route: '/config' }),\n  });\n};\n\nconst schema = {\n  type: 'page',\n  name: 'page',\n  body: [\n    {\n      type: 'form',\n      name: 'form',\n      data: {},\n      title: '',\n      body: [\n        // {\n        //   type: 'input-text',\n        //   id: 'u:11b127c5df46',\n        //   label: 'activeWindow',\n        //   name: 'activeWindow',\n        //   description: '',\n        // },\n        {\n          type: 'combo',\n          label: 'oneAPI',\n          name: 'oneAPI',\n          multiple: true,\n          addable: true,\n          removable: true,\n          removableMode: 'icon',\n          addBtn: {\n            label: '新增',\n            icon: 'fa fa-plus',\n            level: 'primary',\n            size: 'sm',\n            id: 'u:47ecb9e15ff1',\n          },\n          items: [\n            {\n              type: 'input-text',\n              label: 'hostname',\n              name: 'hostname',\n              id: 'u:6496cac4f4b8',\n              description: '',\n            },\n            {\n              type: 'input-text',\n              label: 'apiPath',\n              name: 'apiPath',\n              id: 'u:a701e97d81a6',\n              description: '',\n            },\n            {\n              type: 'switch',\n              label: 'notHttps',\n              option: '',\n              name: 'notHttps',\n              falseValue: false,\n              trueValue: true,\n              id: 'u:a3283c2ac1b6',\n              value: false,\n            },\n            {\n              type: 'input-number',\n              label: 'port',\n              name: 'port',\n              keyboard: true,\n              id: 'u:3d3695bd7ab2',\n              step: 1,\n            },\n            {\n              type: 'input-text',\n              name: 'apiKey',\n              placeholder: '',\n              id: 'u:25b0c7b5e5a0',\n              label: 'apiKey',\n            },\n            {\n              type: 'input-text',\n              label: 'model',\n              name: 'model',\n              id: 'u:ac0737858444',\n              description: '',\n            },\n            {\n              type: 'input-number',\n              label: 'maxTokens',\n              name: 'maxTokens',\n              keyboard: true,\n              id: 'u:a8cfb52c5e43',\n              step: 1,\n            },\n            {\n              type: 'input-number',\n              label: 'temperature',\n              name: 'temperature',\n              keyboard: true,\n              id: 'u:8797d33941aa',\n              step: 1,\n            },\n            {\n              type: 'input-text',\n              label: 'proxyUrl',\n              name: 'proxyUrl',\n              description: '',\n            },\n            {\n              type: 'switch',\n              label: 'use',\n              option: '',\n              name: 'use',\n              falseValue: false,\n              trueValue: true,\n              id: 'u:1ac806d7ad60',\n              value: false,\n            },\n          ],\n          id: 'u:186f183e9320',\n          strictMode: false,\n          syncFields: [],\n          tabsMode: false,\n          draggable: true,\n          draggableTip: '可拖动排序',\n          tabsStyle: 'line',\n          tabsLabelTpl: '表单项${index+1}',\n          multiLine: true,\n          value: [{}],\n        },\n      ],\n      submitText: '',\n    },\n  ],\n  pullRefresh: {\n    disabled: true,\n  },\n  regions: ['body'],\n  style: {\n    boxShadow: ' 0px 0px 0px 0px transparent',\n  },\n  asideResizor: false,\n};\n\nexport const getDynamicFormSchema = () => {\n  schema.body[0].data = getShareData();\n  return schema;\n};\n\nexport const saveDynamicFormSchema = (data: object) => save(data);\n"
  },
  {
    "path": "uTools.js",
    "content": "const path = require('path');\nconst fs = require('fs-extra');\nconst { build } = require('esbuild');\n/**\n * @description\n * @param {string} dirPath\n * @return {string[]}\n */\nfunction getAllFiles(dirPath) {\n  const files = fs.readdirSync(dirPath);\n\n  let result = [];\n\n  // eslint-disable-next-line no-restricted-syntax\n  for (const file of files) {\n    const filePath = `${dirPath}/${file}`;\n    // eslint-disable-next-line no-await-in-loop\n    const stats = fs.statSync(filePath);\n\n    if (stats.isDirectory()) {\n      result = result.concat(getAllFiles(filePath));\n    } else {\n      result.push(filePath);\n    }\n  }\n\n  return result;\n}\n\ngetAllFiles(path.join(__dirname, 'dist', 'uTools'))\n  .filter((s) => s.includes('index.js'))\n  .forEach(async (file) => {\n    const mainFilePath = file\n      .replace(/\\\\/g, '/')\n      .replace('index.js', 'src/main');\n    const mainBundleFilePath = file\n      .replace(/\\\\/g, '/')\n      .replace('index.js', 'src/mainBundle');\n    const content = fs.readFileSync(file).toString();\n    const indexContent = content\n      .replace(\n        'Object.defineProperty(exports, \"__esModule\", { value: true });',\n        `const mainFilePath = \"${mainFilePath}\";`,\n      )\n      .replace('// @ts-ignore', '')\n      .replace(\n        'const main_1 = require(\"./src/main\");',\n        `const main_1 = require(mainFilePath);`,\n      )\n      .replace(\n        '(0, main_1.bootstrap)()',\n        `(0, main_1.bootstrap)(mainFilePath)`,\n      );\n    const indexBundleContent = content\n      .replace(\n        'Object.defineProperty(exports, \"__esModule\", { value: true });',\n        `const mainFilePath = \"${mainBundleFilePath}\";`,\n      )\n      .replace('// @ts-ignore', '')\n      .replace(\n        'const main_1 = require(\"./src/main\");',\n        `const main_1 = require(mainFilePath);`,\n      )\n      .replace(\n        '(0, main_1.bootstrap)()',\n        `(0, main_1.bootstrap)(mainFilePath)`,\n      );\n    fs.writeFileSync(file, indexContent);\n    const indexBundleFile = file\n      .replace(/\\\\/g, '/')\n      .replace('index.js', 'indexBundle.js');\n    fs.writeFileSync(indexBundleFile, indexBundleContent);\n    await build({\n      entryPoints: [`${mainFilePath}.js`],\n      bundle: true,\n      minify: true,\n      // only needed if you have dependencies\n      external: ['electron', 'typescript-json-schema'],\n      platform: 'node',\n      format: 'cjs',\n      outfile: mainFilePath.replace('/main', '/mainBundle.js'),\n    });\n    const conetnt = fs.readFileSync(`${mainFilePath}.js`).toString();\n    fs.writeFileSync(\n      `${mainFilePath}.js`,\n      `const moduleAlias = require('module-alias');\nmoduleAlias.addAlias('@share', '${path\n        .join(__dirname, 'dist', 'share')\n        .replace(/\\\\/g, '/')}');\n\t\t\t\t${conetnt}`,\n    );\n    build({\n      entryPoints: [`${mainFilePath}.js`],\n      bundle: false,\n      minify: false,\n      // only needed if you have dependencies\n      // external: ['electron'],\n      platform: 'node',\n      format: 'cjs',\n      outfile: `${mainFilePath}.js`,\n      allowOverwrite: true,\n    });\n  });\n\n// bundle other files\n['share/uTools/webviewBaseController.js'].forEach(async (file) => {\n  const entryFile = path.join(__dirname, 'dist', file);\n  build({\n    entryPoints: [entryFile],\n    bundle: true,\n    minify: true,\n    // only needed if you have dependencies\n    external: ['electron'],\n    platform: 'node',\n    format: 'cjs',\n    outfile: entryFile.replace('.js', 'Bundle.js'),\n    allowOverwrite: true,\n  });\n});\n\n// 复制物料文件\n\nconst copyDir = () => {\n  const dirPath = path.join(__dirname, 'uTools');\n  const distDirPath = path.join(__dirname, 'dist', 'uTools');\n  const dirNameArry = fs.readdirSync(dirPath);\n  // eslint-disable-next-line no-restricted-syntax\n  for (const dirName of dirNameArry) {\n    const childDirPath = path.join(dirPath, dirName);\n    const stats = fs.statSync(childDirPath);\n    if (stats.isDirectory()) {\n      const copyDirArray = fs.readdirSync(childDirPath);\n      // eslint-disable-next-line no-restricted-syntax\n      for (const copyDirName of copyDirArray) {\n        if (copyDirName !== 'script') {\n          const copyDirPath = path.join(childDirPath, copyDirName);\n          fs.copySync(\n            copyDirPath,\n            path.join(distDirPath, dirName, copyDirName),\n          );\n        }\n      }\n    }\n  }\n};\ncopyDir();\n"
  },
  {
    "path": "uToolsUpload.js",
    "content": "const path = require('path');\nconst OSS = require('ali-oss');\nconst tar = require('tar');\nconst fs = require('fs-extra');\n\nconst tempPath = path.join(__dirname, '.lowcode', 'dist');\nconst file = path.join(__dirname, '.lowcode', 'download.tar.gz');\n\nfs.copySync(\n  path.join(__dirname, 'dist', 'uTools'),\n  path.join(tempPath, 'uTools'),\n);\n\nfs.copySync(\n  path.join(__dirname, 'dist', 'share/uTools/webviewBaseControllerBundle.js'),\n  path.join(tempPath, 'share/uTools/webviewBaseControllerBundle.js'),\n);\n\nconst dirNameArray = fs.readdirSync(path.join(tempPath, 'uTools'));\n// eslint-disable-next-line no-restricted-syntax\nfor (const dirName of dirNameArray) {\n  const scriptPath = path.join(tempPath, 'uTools', dirName, 'script');\n  fs.removeSync(path.join(scriptPath, 'index.js'));\n  const files = fs.readdirSync(path.join(scriptPath, 'src'));\n  files.forEach((f) => {\n    if (f !== 'mainBundle.js') {\n      fs.removeSync(path.join(path.join(scriptPath, 'src'), f));\n    }\n  });\n}\n\nconst upload = async () => {\n  await tar.create(\n    {\n      gzip: true,\n      file,\n      cwd: path.join(__dirname, '.lowcode'),\n    },\n    ['dist'],\n  );\n\n  if (process.env.bucket) {\n    const store = new OSS({\n      region: 'oss-cn-beijing',\n      accessKeyId: process.env.accessKeyId,\n      accessKeySecret: process.env.accessKeySecret,\n      bucket: process.env.bucket,\n    });\n    store.put('download-free.tar.gz', file).then((result) => {\n      fs.removeSync(path.join(__dirname, '.lowcode'));\n      console.log(result.url);\n    });\n  }\n};\n\nupload();\n"
  }
]